-- W A R N I N G : some invalid deprecated tags /******************************************************* ** generated in the:17-12-14T16:11 by frenchi\stefano@FRENCHI from utility_new ** latest objs to 171214:sp__script *******************************************************/ set nocount on declare @db sysname,@svr sysname, @emsg nvarchar(2048),@esev int,@ests int select @db=db_name(), @svr=@@servername if @svr='FRENCHI\SQLEXPRESS0' and @db='utility' begin raiserror('Cannot execute from db where originated.', 11,1) with nowait goto end_of_script end -- check db version if (select cmptlevel from master..sysdatabases where [name]=@db )<90 begin raiserror('DB compatibility level must be at least 90 (MSSql2k5)', 10,1) with nowait raiserror('Please run "exec sp_dbcmptlevel ''%s'', 90"', 10,1,@db) with nowait raiserror('',11,1) with nowait goto end_of_script end -- for versioning declare @aut sysname, -- store author @ver decimal(14,4), -- used to store new obj version @msg nvarchar(128), -- generic message string @repeat int -- number of repeat of script -- if error of unknow obj, script is -- repeated bacause dependencies if object_id('tempdb..#script_results') is null create table #script_results( id int identity, dt datetime default(getdate()) not null, who sysname default system_user+'@'+isnull(host_name(),'???'), grp sysname not null, rep int null, number int null, message nvarchar(2048) not null, severity int not null, state int null, line int null, [procedure] sysname null ) if object_id('tempdb..#script_catch') is null exec(' create proc #script_catch @grp sysname,@repeat int as begin insert #script_results(dt,grp,rep,number,message,severity,state,line,[procedure]) select getdate(),@grp,@repeat, error_number(),isnull(error_message(),''n/s''), error_severity(),error_state(), error_line(),error_procedure() end ') select @repeat=1 begin_of_script: -- ########################## -- ## -- ## disable trace db; -- ## hope nobody work on important things while upgrade -- ## -- ######################################################## if not object_id('sp__script_trace_db') is null exec sp__script_trace_db 'uninstall' -- ########################## -- ## -- ## core objects has different version check -- ## -- ######################################################## -- ============================================================= fn__script_sign raiserror('drop&create "fn__script_sign"',10,1) if exists( select top 1 null from sys.objects where name='fn__script_sign' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_sign] exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131123\s.zaglio: added default exclusion of charset&collation v:130730.1154,130729\s.zaglio: see comments into code v:130709\s.zaglio: changed to use hash v:130406\s.zaglio: added sign of jobs v:120821\s.zaglio: added sign of views v:120730\s.zaglio: added @detail 4 for sign of pure struct, without names v:120517\s.zaglio: removed core group v:120516\s.zaglio: return a checksum sign of current db object d:120516\s.zaglio: fn__crc32_table t:sp__script_sign_test t:select dbo.fn__script_sign(''fn__sysobjects'',1) t:select dbo.fn__script_sign(''fn__script_sign'',1) */ CREATE function fn__script_sign(@obj sysname = null,@detail tinyint = null) returns numeric(14,4) as begin declare @xtype varchar(2),@ver numeric(14,4),@obj_id int, @src nvarchar(max),@n int select @obj_id=object_id(@obj),@detail=isnull(@detail,0),@src='''' -- details for non jobs: -- bit_val meaning -- 0/null table columns or params of sp/fn, without defaults -- 1 table columns with index or params of sp/fn with body -- 2 table columns or params of sp/fn without names, without defaults -- 4 table columns with index or params of sp/fn without names -- details for jobs: -- bit_val meaning -- 0/null names/status of jobs -- 1 names/status of jobs with names,commands,flags,outfile of steps -- 2 status of jobs -- 6 status of jobs with commands,flags,outfile of steps without names if left(@obj,2)!=''j:'' begin select @xtype=xtype from sysobjects where id=@obj_id if @xtype is null return null if @xtype in (''U'',''V'') begin select @src=@src+txt+char(13) from ( select case when @detail&4=4 then '''' else column_name+''|'' end+ cast(ordinal_position as varchar)+''|''+ isnull(column_default,'''')+''|''+is_nullable+''|''+data_type+''|''+ isnull(cast(character_maximum_length as varchar),'''')+''|''+ isnull(cast(character_octet_length as varchar),'''')+''|''+ isnull(cast(numeric_precision as varchar),'''')+''|''+ isnull(cast(numeric_precision_radix as varchar),'''')+''|''+ isnull(cast(numeric_scale as varchar),'''')+''|''+ isnull(cast(datetime_precision as varchar),'''')+''|''+ case when @detail&8=0 then '''' else isnull(character_set_name,'''')+''|''+ isnull(collation_name,'''') end as txt -- select top 100 * from information_schema.columns with (nolock) where table_name=@obj ) tbl if @detail&1=1 select @src=@src+txt+char(13) from ( select -- consider only structure, not the position on ownership -- [filegroup]+''|''+ case when @detail&4=4 then '''' else parentname+''|'' end+ -- parentowner+''|''+ case when @detail&4=4 then '''' else indexname+''|''+columnname+''|'' end+ cast(descending as char)+''|''+cast(is_included_column as char)+''|''+ cast([clustered] as char)+''|''+cast([unique] as char)+''|''+ cast(uniqueconstraint as char)+''|''+cast([primary] as char)+ cast([norecompute] as char)+''|''+cast(ignoredupkey as char) as txt, ord as ord from ( -- declare @tbl sysname select @tbl=''log_ddl'' select sysfilegroups.groupname as [filegroup], sysobjects.name as parentname, sysusers.name as parentowner, sysindexes.name as indexname, syscolumns.name as columnname, convert(bit,isnull(indexkey_property(syscolumns.id,sysindexkeys.indid,keyno,''isdescending''), 0)) as descending, convert(bit,0) as is_included_column, convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isclustered'')) as [clustered], convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isunique'')) as [unique], convert(bit,case when (sysindexes.status & 4096) = 0 then 0 else 1 end) as uniqueconstraint, convert(bit,case when (sysindexes.status & 2048) = 0 then 0 else 1 end) as [primary], convert(bit,case when (sysindexes.status & 0x1000000) = 0 then 0 else 1 end) as [norecompute], convert(bit,case when (sysindexes.status & 0x1) = 0 then 0 else 1 end) as ignoredupkey, sysindexes.name+''|''+right(''00000''+cast(sysindexkeys.keyno as varchar),5) as ord from sysindexes with (nolock) -- select * from sysindexes where name=''ix_log_ddl'' inner join sysindexkeys with (nolock) -- select * from sysindexkeys where indid=2 and id=2103730597 on sysindexes.indid = sysindexkeys.indid -- select * from sys.indexes where name=''ix_log_ddl'' and sysindexkeys.id = sysindexes.id -- select * from sys.indexkeys where indid=2 and id=2103730597 inner join syscolumns with (nolock) -- select * from syscolumns where id=2103730597 and colid in (1,6,12,4) on syscolumns.colid = sysindexkeys.colid -- select * from sys.index_columns where object_id=2103730597 and index_id=2 and syscolumns.id = sysindexes.id inner join sysobjects with (nolock) on sysobjects.id = sysindexes.id left join sysusers with (nolock) on sysusers.uid = sysobjects.uid left join sysfilegroups with (nolock) on sysfilegroups.groupid = sysindexes.groupid where (objectproperty(sysindexes.id,''istable'') = 1 or objectproperty(sysindexes.id,''isview'') = 1) and objectproperty(sysindexes.id,''issystemtable'') = 0 and indexproperty(sysindexes.id,sysindexes.name,N''isautostatistics'') = 0 and indexproperty(sysindexes.id,sysindexes.name,N''ishypothetical'') = 0 and sysindexes.name is not null and sysobjects.name=@obj ) cols ) tbl end -- table sign else -- if job begin if @detail&1=0 select @src=@src+txt+char(13) from ( select case when @detail&4=0 then specific_schema+''|'' else '''' end+ cast(ordinal_position as varchar)+''|''+ parameter_mode+''|''+ case when @detail&4=0 then parameter_name+''|'' else '''' end+ data_type+''|''+ isnull(cast(character_maximum_length as varchar),'''')+''|''+ isnull(cast(character_octet_length as varchar),'''')+''|''+ isnull(cast(numeric_precision as varchar),'''')+''|''+ isnull(cast(numeric_precision_radix as varchar),'''')+''|''+ isnull(cast(numeric_scale as varchar),'''')+''|''+ isnull(cast(datetime_precision as varchar),'''')+''|''+ isnull(character_set_name,'''')+''|''+isnull(collation_name,'''') as txt -- select top 100 * from information_schema.parameters with (nolock) where specific_name=@obj ) tbl else begin select top 1 @src=left(definition,4000) from sys.sql_modules with (nolock) where object_id=@obj_id declare @p1 int,@p2 int, @p3 int select @p1=patindex(''%[vr]:%'',@src) if @p1>0 begin select @src=substring(@src,@p1+2,128),@p1=1 select @p2=patindex(''%[,\]%'',@src) select @src=substring(@src,@p1,@p2-@p1) select @ver=cast(@src as numeric(10,4)) end end end -- any other obj end -- non jobs else begin -- select dbo.fn__script_sign(''j:%'',default) -- tested&verified -- select dbo.fn__script_sign(''j:%'',2) -- tested&verified -- select dbo.fn__script_sign(''j:%'',1) -- tested&verified -- select dbo.fn__script_sign(''j:%'',6) -- tested select @obj=substring(@obj,3,128) select @src=@src+txt+char(13) from ( select case when @detail&2!=2 then name+''|'' else '''' end+ cast(enabled as char(1)) as txt from msdb..sysjobs where name like @obj -- nb: the order do not influence the result ) jobs if @detail&1=1 or @detail&4=4 select @src=@src+txt+char(13) from ( select top 100 percent len(command) lcmd, case when @detail&4!=4 then step_name+''|'' else '''' end+ command+''|''+cast(flags as nvarchar(5))+''|''+ isnull(output_file_name,'''') as txt from msdb..sysjobs j join msdb..sysjobsteps js on j.job_id=js.job_id where j.name like @obj ) jobs end -- jobs /* 130730: it looks like source code is different from case and case, so the source hash is not correct with the effect that destination is continously recompiled; so I converted sign of vi/fn/sp back to get first r/v tag and the rest is returned as crc32 that fit the numeric integer part of version */ if @ver is null begin declare @chk int select @chk=0 ;with a as (select 1 as n union all select 1) -- 2 ,b as (select 1 as n from a ,a a1) -- 4 ,c as (select 1 as n from b ,b b1) -- 16 ,d as (select 1 as n from c ,c c1) -- 256 ,e as (select 1 as n from d ,d d1) -- 65,536 ,f as (select 1 as n from e ,e e1) -- 4,294,967,296=17+trillion chrs ,factored as (select row_number() over (order by n) rn from f) ,factors as (select rn,(rn*4000)+1 factor from factored) select @chk = @chk ^ checksum( substring( cast(@src as varbinary(max)), factor - 4000, 4000 ) ) from factors where rn <= ceiling(datalength(cast(@src as varbinary(max)))/(4000.0)) select @ver=@chk end return @ver end -- fn__script_sign' -- ======================================================================== tids select @ver=dbo.fn__script_sign('tids',1) if not @ver is null and @ver=108162603.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'tids') with nowait goto skip_tids end raiserror('re-creating "%s.%s"',10,1,@db,'tids') with nowait if exists( select top 1 null from sys.objects where name='tids' and schema_id=schema_id('dbo') ) drop view [dbo].[tids] begin try exec dbo.sp_executesql @statement = N'/* leave this for other app l:see LICENSE file g:obj,utility v:131006\s.zaglio: updated v:120517\s.zaglio: generic types */ CREATE view [tids] as select 0 as free, -- the record can be replaced or id reused 1 as cnt, -- counter 2 as tid , -- type id masker 3 as flg , -- flags definition 4 as seq , -- sequence type 5 as mem , -- memory 6 as obj , -- generic object 7 as usr , -- user name 8 as host, -- host name 9 as srv , -- server (131006\s.zaglio: modified from svr) 10 as app , -- application 11 as ev , -- event 12 as code, -- code/programming/line of text 13 as tsk , -- task, job, activity, actions, etc. 14 as range, -- range values 15 as grp , -- used for groups, lists, etc. 16 as db , -- database 17 as email, -- email record 18 as html, -- html record 19 as body, -- body of email or html 20 as iospc, -- i/o specific 21 as ioseg, -- i/o specific segment 22 as url, -- unified resource locator 23 as [file], -- file name 24 as [dir], -- dir for file (parent); the path is the url 25 as [prop], -- property -1 as [tid.last]-- (131006\s.zaglio: modified from tids.last)' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_tids: -- ======================================================================= flags select @ver=dbo.fn__script_sign('flags',1) if not @ver is null and @ver=1413502072.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'flags') with nowait goto skip_flags end raiserror('re-creating "%s.%s"',10,1,@db,'flags') with nowait if exists( select top 1 null from sys.objects where name='flags' and schema_id=schema_id('dbo') ) drop view [dbo].[flags] begin try exec dbo.sp_executesql @statement = N'/* leave this for other app l:see LICENSE file g:obj,utility v:131006\s.zaglio: updated v:120517\s.zaglio: global flags */ CREATE view [flags] as select 1 as A, 2 as B, 4 as C, 8 as D, 16 as E, 32 as F, 64 as G, 128 as H, 256 as I, 512 as J, 1024 as K, 2048 as L, 4096 as M, 8192 as N, 16384 as O, 32768 as P, 512 as srv , -- concerning the server 1024 as db , -- concerning the database 2048 as ddl , -- concerning Data Definition Language 512 as ver , -- 1=version/0=release flag 512 as RA , -- replaces accented 48 as type, -- segment type 0 as SEG , -- generic 32 as #FLT, -- filter 16 as #GRP, -- group 48 as #COM, -- comment 512 as RPT , -- repeat 1024 as HDR , -- header 2048 as DTL , -- detail 4096 as FTR , -- footer 8192 as SCR , -- scramble -- iof 32 as [iof.wrong], 64 as [iof.processed], -- fn__script_sysobjs and ex fn__script_events 16 as [sys], -- system 32 as [tmp], -- temporary 64 as [exclude], -- eXclude -- sp__dir, sp__ftp and files 32 as [files.directory], 64 as [files.download], 128 as [files.upload], 256 as [files.delete], 512 as [files.ok], 1024 as [files.err], -1 as [flags.last]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_flags: -- ===================================================================== fn__sym select @ver=dbo.fn__script_sign('fn__sym',1) if not @ver is null and @ver=130614.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__sym') with nowait goto skip_fn__sym end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sym') with nowait if exists( select top 1 null from sys.objects where name='fn__sym' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sym] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130614\s.zaglio: added _ to non word and sentence v:130612\s.zaglio: added bounds,non_word,non_sentence v:120517\s.zaglio: removed from core group v:120201\s.zaglio: added to core group v:111222\s.zaglio: added gcs,gce,lcc v:111111\s.zaglio: added space v:100404\s.zaglio: added return values v:100328\s.zaglio: changed to table function and expanded to more symbols replace old fn__crlf,fn__seps v:091027\s.zaglio: for simplicity t: sp__find ''fn__crlf'' sp__find ''fn__seps'' sp__find ''char(13)'' sp__find ''char(10)'' sp__find ''char(9)'' todo: replace all char(13),char(10),char(9) */ CREATE function [dbo].[fn__sym]() returns table as return select -- classic txt symbols char(ascii('' '')) [space], char(13) cr,char(10) lf,char(13)+char(10) crlf,char(9) tab, -- path separators ''\'' psep, ''/'' usep, -- returns values 0 ok, -1 help, -- group comment start and end ''/*'' gcs, ''*/'' gce, -- line code commend ''--'' lcc, -- bounds of a (t)sql word ''s''''"_*+/,.;:\<>()=¬''+char(13)+char(10)+'' ''+char(9) bounds, ''%[^a-z0-9_]%'' non_word, ''%[^a-z0-9 _]%'' non_sentence -- end fn__sym' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sym: -- =============================================================== fn__str_parse select @ver=dbo.fn__script_sign('fn__str_parse',1) if not @ver is null and @ver=121226.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__str_parse') with nowait goto skip_fn__str_parse end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_parse') with nowait if exists( select top 1 null from sys.objects where name='fn__str_parse' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_parse] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:121226\s.zaglio: remake c:http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings v:121004\s.zaglio: remake using patindex and removed a bug v:120517\s.zaglio: removed from core group v:110630\s.zaglio: added to core group v:100418\s.zaglio: a bug near out of indx v:100221\S.Zaglio: return piece of string separated by one of char in @sym t: print isnull(dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',0),''?'') -- ? print dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',1) -- drive: print dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',2) -- dir print dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',3) -- subdir print dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',4) -- file print dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',5) -- ext print isnull(dbo.fn__str_parse(''drive:\dir\subdir\file.ext'',''\.'',6),''?'') -- ? select dbo.fn__str_parse(''a;b;'','';,'',1),dbo.fn__str_parse(''a;b;'','';,'',2) -- a,b select dbo.fn__str_parse(''a;b;'','';,'',3),dbo.fn__str_parse(''a;b;'','';,'',4) -- '''',null */ CREATE function [dbo].[fn__str_parse]( @tokens nvarchar(4000), @sym nvarchar(32), @pos int ) returns nvarchar(4000) as begin declare @token nvarchar(4000) ;with e1(n) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1), e2(n) as (select 1 from e1 a, e1 b), e4(n) as (select 1 from e2 a, e2 b), e42(n) as (select 1 from e4 a, e2 b), ctetally(n) as (select 0 union all select top (datalength(isnull(@tokens,1))) row_number() over (order by (select null)) from e42), ctestart(n1) as (select t.n+1 from ctetally t where (substring(@tokens,t.n,1) like ''[''+@sym+'']'' or t.n = 0)), limits(n1,n2) as ( select s.n1, isnull((select top 1 n1 from ctestart e where e.n1>s.n1 order by 1),len(@tokens)+2) n2 from ctestart s ), tokens(pos,token) as ( select pos=row_number() over (order by (select null)), token=substring(@tokens,n1,n2-n1-1) from limits ) select @token=token from tokens where pos=@pos return @token end -- [fn__str_parse]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_parse: -- ======================================================== fn__script_info_tags select @ver=dbo.fn__script_sign('fn__script_info_tags',1) if not @ver is null and @ver=140119.1000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__script_info_tags') with nowait goto skip_fn__script_info_tags end raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_info_tags') with nowait if exists( select top 1 null from sys.objects where name='fn__script_info_tags' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_info_tags] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script todo:manage multiline tags;manage /**/ into '''' v:140119.1000\s.zaglio:again syntax near tags of 0 lenght v:140113.1002\s.zaglio\z.aglio: better syntax parses v:131103\s.zaglio:converted @row into @lvl and row into row of code v:131129\s.zaglio:added maxrecurtion to 1st with v:131126\s.zaglio:added management of r3;r2;r1 and c3;c2;c1 v:130907\s.zaglio:added tag # v:130602\s.zaglio:added management of r3,r2,r1 in comments v:130528\s.zaglio:better end comments finding and used maxrecursion v:130523\s.zaglio:a bug where more spaces after create v:130522\s.zaglio:resolved bug near lf and changed results to nvarchar v:130511;121206\s.zaglio:a remake using with;added monoline tag S (scope) and J (job) v:120724,120517\s.zaglio:added tag x;removed from core group v:120510,111229\s.zaglio:a bug when comments greather than 4k;a small bug v:111222\s.zaglio:limited to /* ... */ with backward compatibility v:110630\s.zaglio:added to core grp v:110628,110624\s.zaglio:added deprecated;vesioned r:110614\s.zaglio:used only fn__str_parse;called from fn__script_info,sp__trace t:sp__script_info_tags_test @dbg=1 t:select object_name(obj_id) name,* from fn__script_info(null,default,default) t:select object_name(obj_id) name,* from fn__script_info(null,''g'',default) t:select * from dbo.fn__script_info(''fn__script_info_tags'',''rv#'',0) t:select * from dbo.fn__script_info(''fn__script_info_tags'',''rv#'',default) t:select object_name(obj_id) obj,* from fn__script_info(null,''d'',default) -- deprecard t:sp__Script_store @opt=dis -- c:old style */ CREATE function fn__script_info_tags( @buf nvarchar(max)=null, -- top comment of sp,fn,v,etc. @grps sysname=null, @lvl tinyint=null -- row 0 is top of group,cmd pos ) returns @tag table ( tag nvarchar(8), -- l,g,v,d,s,todo,# row smallint, -- row of code val1 nvarchar(4000), -- date(rvd),grp(g),cmd,cmt(c) val2 nvarchar(4000) null, -- user,2nd grp,object type val3 nvarchar(4000) null, -- comment,3rd grp,object status smallint null -- status of syntax of comments ) as begin -- ============================================================= declarations == declare @lines table ( pos int primary key, tag nvarchar(8), line nvarchar(4000), pslash smallint null, pcolon smallint null, pcom1 smallint null, pcom2 smallint null, pcom3 smallint null, ln smallint ) declare @line nvarchar(4000), @cr nchar(1),@lf nchar(1),@crlf nchar(2), @tab nchar(1),@i int,@j int,@k int,@st sysname, @pcmd int, @cmd sysname, @otype sysname, @oname sysname, @kind sysname,@tck varchar(16),@c nchar,@dbgt xml; select @grps=isnull(@grps,''lkbvrjgbsctodo#''), -- sp__Style @cr=cr,@lf=lf,@crlf=crlf,@tab=tab from fn__sym() -- ===================================================================== body == -- if @dbg=1 insert @tag(row,tag,val1,val2,val3) select 62,''dbg'',null,null,null /* extract create/alter [type] and object name proc func view tabl syno trig */ -- search correct create/alter proc/func/... -- skip initial comments /*...*/ and /*../*..*/..*/ select @kind=''[pfvts][ruiay][onebi][cwlog]'' select @k=patindex(''%create %''+@kind+''%'',@buf) if @k=0 select @k=patindex(''%alter %''+@kind+''%'',@buf) select @i=charindex(''/*'',@buf),@j=charindex(''*/'',@buf,@i+2) if @i>0 and @k>@i begin while @i<@j begin select @i=charindex(''/*'',@buf,@i+2) if @i=0 or (@i>@j and @i>@k) break if @i<@j select @j=charindex(''*/'',@buf,@j+2) end select @j=@j+2 if @k>@j select @j=@k end else select @j=@k -- @j contain the last closed comment or 0 -- must be skipped blank lines and -- comment -- strip headers and search for create/alter proc/func/view/trigger/synonym select @line=substring(@buf,@j,256) select @pcmd=patindex(''%create %''+@kind+''%'',@line) if @pcmd=0 select @pcmd=patindex(''%alter %''+@kind+''%'',@line) if @pcmd!=0 begin -- extract declaration line and move all into single line select @line=replace(substring(@line,@pcmd,200),@tab,'' '') select @pcmd=@pcmd+@j+2 -- absolute position select @line=replace(replace(replace(@line,@crlf,@cr),@lf,@cr),@cr,'' '') -- reduce spaces while (charindex('' '',@line)>0) select @line=replace(@line,'' '','' '') while (charindex(''. '',@line)>0) select @line=replace(@line,''. '',''.'') while (charindex('' .'',@line)>0) select @line=replace(@line,'' .'',''.'') while (charindex(''[ '',@line)>0) select @line=replace(@line,''[ '',''['') while (charindex('' ]'',@line)>0) select @line=replace(@line,'' ]'','']'') end -- parse alter/create instruction ;with splits(pos, start, [stop]) as ( select 1, 1, charindex('' '', @line) union all select pos + 1, [stop] + 1, charindex('' '', @line, [stop] + 1) from splits where [stop] > 0 ) ,tokens as ( select pos, ltrim( substring( @line, start, case when [stop] > 0 then [stop]-start else 256 end ) ) as token from splits ) select @cmd=case when pos=1 then token else @cmd end, @otype=case when pos=2 then token else @otype end, @oname=case when pos=3 then token else @oname end from tokens where pos<4 option (maxrecursion 1000) select @i=charindex(''('',@oname) if @i>0 select @oname=left(@oname,@i-1) select @oname=isnull(quotename(parsename(@oname,2))+''.'','''') +quotename(parsename(@oname,1)) -- reduce to header to not occur into max occurence of 1000 select @buf=substring(@buf,1,@pcmd) -- correct unix \n to uncorrect \n windows style and tab to space select @buf=replace(replace(replace(@buf,@crlf,@cr),@lf,@cr),@tab,'' '') /* debug session -- select * from dbo.fn__script_info(''fn__script_info_tags'',default,0) insert @tag(row,tag,val1,val2,val3) select 75,''dbg'',@buf,null,null */ -- split top comment into lines ;with splits(pos, start, [stop]) as ( select 1, cast(1 as int), charindex(@cr, @buf) union all select pos + 1, cast([stop] + (datalength(@cr)/2) as int), charindex(@cr, @buf, [stop] + (datalength(@cr)/2)) from splits where [stop] > 0 ) ,lines as ( select pos, ltrim( substring( @buf, start, case when [stop] > 0 then [stop]-start else 4000 end ) ) as line from splits ) /* unfortunatelly a more sub withs cannot be used for unknown problemi with substring or left or charindex due some inner optimization of the engine */ ,tags as ( select pos, case when charindex('':'',line)>0 then left(line,charindex('':'',line)-1) else '''' end as tag, case when charindex('':'',line)>0 then ltrim(rtrim(substring(line,charindex('':'',line)+1,4000))) else ltrim(rtrim(line)) end as line from lines ) ,epured as ( select pos,ltrim(replace(tag,''--'','''')) as tag/*old line style */,line from tags ) insert @lines(pos,tag,line,pslash,pcolon,pcom1,pcom2,pcom3,ln) select pos,left(tag,8),line, nullif(isnull( nullif(isnull( nullif(charindex(''\'',line),0), charindex(''/'',line)),0), case -- case v:yyyymmaa:{space}comment when charindex('' '',line)0 or @grps is null) option (maxrecursion 1000) -- code for debug select @dbgt = (select * from @lines for xml auto) /* debug session -- select * from dbo.fn__script_info(''fn__script_info_tags'',default,default) insert @tag(row,tag,val1,val2,val3) select 158,''dbg'',pos,tag,line from @lines return */ -- extract group components ;with tags as ( select tag, row_number() over(partition by tag order by pos)-1 as lvl, ltrim(rtrim(substring(line,1,isnull(pcom1-1,ln)))) as val1, ltrim(rtrim(substring(line,pcom1+1,isnull(pcom2-1,ln)-pcom1))) as val2, ltrim(rtrim(substring(line,pcom2+1,isnull(pcom3-1,ln)-pcom2))) as val3, pos from @lines where tag in (''g'',''s'') and ln>0 ) insert @tag(tag,row,val1,val2,val3) select tag,pos,val1,val2,val3 from tags where @lvl is null or @lvl=lvl option (maxrecursion 1000) -- extract revisions components ;with tags as ( select tag, row_number() over( -- row 0 of a revision is the 1st r or v partition by case tag when ''r'' then ''v'' else tag end order by pos )-1 as lvl, pos as row, ltrim(rtrim(substring(line,1,isnull(pslash-1,isnull(pcolon-1,ln))))) as val1, ltrim(rtrim(substring(line,pslash+1,isnull(pcolon-1,ln)-pslash))) as val2, ltrim(rtrim(substring(line,pcolon+1,ln-pcolon))) as val3 from @lines where tag in (''v'',''r'',''d'',''x'',''o'') and ln>0 ) insert @tag(tag,row,val1,val2,val3) select tag,row,val1,val2,val3 from tags where @lvl is null or @lvl=lvl option (maxrecursion 1000) -- select * from fn__script_info(''fn__script_info_tags'',''rv'',default) -- reduce r3,r2,r1 or r3;r2;r1 into r3; reduce c3;c2;c1 into c3 update @tag set val1=left(val1,isnull(nullif(charindex('','',val1),0),charindex('';'',val1))-1), val3=left(val3,isnull(nullif(charindex('';'',val3),0),len(val3)+1)-1) where tag in (''r'',''v'') and (charindex('','',val1)>0 -- ??and charindex('','',val1,charindex('','',val1))>0?? or charindex('';'',val1)>0) -- extract single tag component ;with tags as ( select tag, row_number() over(partition by tag order by pos)-1 as lvl, line as val1, pos from @lines where tag in (''l'',''c'',''t'',''k'',''todo'') ) insert @tag(tag,row,val1) select tag,pos,val1 from tags where @lvl is null or @lvl=lvl option (maxrecursion 1000) if charindex(''#'',@grps)>0 begin -- if isnull(@pcmd,0)=0 select @i=''create/alter not found'' insert @tag(tag,row,val1,val2,val3) select ''#'',@pcmd,@cmd,@otype,@oname end -- apply convert into datetime and adjustments return end -- fn__script_info_tags' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__script_info_tags: -- ============================================================= fn__script_info select @ver=dbo.fn__script_sign('fn__script_info',1) if not @ver is null and @ver=140124.1000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__script_info') with nowait goto skip_fn__script_info end raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_info') with nowait if exists( select top 1 null from sys.objects where name='fn__script_info' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_info] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script todo:manage multiline tags v:140124.1000\s.zaglio:removed limits near comment parse v:131103.1000\s.zaglio:adapted to new fn__script_info_tags v:130925\s.zaglio:a bug near with (...datalength(''|'')/2...) v:130907\s.zaglio:adapted to fn__script_into_tags v:130528\s.zaglio:removed dep from fn__str_table_fast and fn__comments v:130523.1200\s.zaglio:a bug when @objs was null and added xt fld and minor other v:130522\s.zaglio:no more compatible with mssql2k and optimized @obj to @objs v:120517\s.zaglio:removed from core group v:110629.1600\s.zaglio:added obj name to output and isolted from fn__ismssql2k v:110628\s.zaglio:added info about db trigger v:110627\s.zaglio:versioned r:110314\s.zaglio:added use of fn__script_info_tags r:100523\s.zaglio:a bug into row value r:100518\s.zaglio:managed line commented tags r:100417\s.zaglio:return info contained in tag of header c:########################################################## c:########## CORE FUNCTION, DO NOT CALL OTHERs ############# c:########################################################## t:sp__usage ''fn__Script_info'' t: -- multiline t (todo: manage this sub-tag) select * from fn__script_info(''sp__style'',default,default) select * from fn__script_info(''fn__script_info'',default,default) select * from fn__script_info(''fn__script_info'',''rv'',default) select * from fn__script_info(''fn__script_info'',''r'',0) t:select object_name(obj_id) name,* from fn__script_info(null,default,default) t:select object_name(obj_id) name,* from fn__script_info(null,''g'',default) t:select * from dbo.fn__script_info(''sp__script_group'',''vr'',default) t:select * from dbo.fn__script_info(''tr__script_trace_db'',''gvr'',default) t:select * from dbo.fn__script_info(''fn__script_info|sp__util_%'',default,default) t:select * from dbo.fn__script_info(''unknown'',default,default) t:select * from dbo.fn__script_info(''tst_test'',default,default) -- c:old style */ CREATE function [dbo].[fn__script_info]( @objs sysname=null, -- all sp,fn,v,etc. @grps sysname=null, @lvl tinyint=null -- tag level (0 is top of group) ) returns @t table ( obj_id int, obj sysname, xt varchar(2) null, tag nvarchar(4) null, -- l,g,v,d row smallint null, -- row of code val1 nvarchar(4000) null, -- date,grp,deprecated val2 nvarchar(4000) null, -- user,comment,2nd grp val3 nvarchar(4000) null -- 3rd grp ) as begin declare @r int,@id int,@buf nvarchar(max),@obj sysname declare @objects table (id int,obj sysname,xt varchar(2),nfo nvarchar(256)) -- get objects ;with pieces(pos, start, [stop]) as ( select 1, 1, charindex(''|'', @objs) union all select pos + 1, [stop] + 1, charindex(''|'', @objs, [stop] + 1) from pieces where [stop] > 0 ), splits as ( select pos, substring( @objs, start, case when [stop] > 0 then [stop]-start else 4000 end ) as token from pieces ) -- ;with splits as (select 1 as pos,@objs as token) insert @objects (id,obj,xt) select id,[name],xtype from sysobjects o cross apply splits where (o.name like replace(token,''_'',''[_]'') or @objs is null) and xtype in (''P'',''V'',''TF'',''FN'',''IF'',''FI'',''TR'') union -- special cases for db triggers select object_id as id,[name],''TD'' from sys.triggers o cross apply splits where (o.name like replace(token,''_'',''[_]'') or @objs is null) and parent_id=0 -- means db trigger -- fill tag info (one or more per object) insert @t(obj_id,obj,xt,row,tag,val1,val2,val3) select id,obj,xt,row,tag,val1,val2,val3 from @objects o join sys.sql_modules m on m.object_id=o.id cross apply fn__script_info_tags([definition],@grps,@lvl) t -- add not tagged objects if not @grps in (''d'') insert @t(obj_id,obj,xt) select o.id,o.obj,o.xt from @objects o left join @t t on o.id=t.obj_id where t.obj_id is null return end -- fn__script_info' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__script_info: -- ============================================================= fn__script_drop select @ver=dbo.fn__script_sign('fn__script_drop',1) if not @ver is null and @ver=131001.1100 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__script_drop') with nowait goto skip_fn__script_drop end raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_drop') with nowait if exists( select top 1 null from sys.objects where name='fn__script_drop' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_drop] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:get,create,drop,script,if,exists v:131001.1100\s.zaglio: refined drop of pk r:130908\s.zaglio: return drop scripts t:sp__sysobjects_test */ CREATE function fn__script_drop( @obj sysname, @typ nvarchar(2), @schema sysname, @parent sysname, @opt sysname ) returns table as return /* AF = funzione di aggregazione (CLR) C = vincolo CHECK D = DEFAULT (vincolo o valore autonomo) F = vincolo FOREIGN KEY FN = funzione scalare SQL FS = Funzione scalare di assembly (CLR) FT = funzione valutata a livello di tabella assembly (CLR) IF = funzione SQL inline valutata a livello di tabella IT = tabella interna P = Stored procedure SQL PC = Stored procedure di assembly (CLR) PG = Guida di piano PK = vincolo PRIMARY KEY R = regola (tipo obsoleto, autonoma) RF = procedura-filtro-replica S = tabella di base di sistema SN = sinonimo SQ = coda di servizio TA = trigger DML assembly (CLR) TF = funzione valutata a livello di tabella SQL TR = trigger DML SQL TT = tipo tabella U = tabella (definita dall''utente) UQ = vincolo UNIQUE V = vista X = stored procedure estesa */ select @obj as [obj], @typ as [type], @schema as [schema], drop_script= case when @typ=''PK'' then ''alter table ''+ isnull(q_schema+''.'','''')+q_parent+ '' drop constraint ''+quotename(@obj) else ''drop ''+ case when @typ in (''PK'',''UQ'',''F'') then ''index ''+isnull(q_schema+''.'','''') +isnull(q_parent+''.'','''') +q_obj else case when @typ in (''FN'',''TF'',''IF'') then ''function '' when @typ in (''TR'',''TD'') then ''trigger '' when @typ=''SN'' then ''synonym '' when @typ=''U'' then ''table '' when @typ=''P'' then ''proc '' when @typ=''V'' then ''view '' when @typ=''D'' then ''constraint '' when @typ in (''FN'',''IF'',''TF'') then ''function '' else ''#!unktype '' end+ isnull(q_schema+''.'','''')+q_obj end+case @typ when ''TD'' then '' on database'' else '''' end end, -- pk if_exists= ''if exists(''+crlf+ case when @typ in (''IX'',''UQ'') then '' select top 1 null from sys.indexes''+crlf+ '' where name=''''''+@obj+''''''''+crlf+ '' and object_id=object_id(''''''+ q_Schema+''.''+q_parent+ '''''')''+crlf when @typ in (''TD'') then '' select top 1 null from sys.triggers''+crlf+ '' where name=''''''+@obj+''''''''+crlf else '' select top 1 null from sys.objects''+crlf+ '' where name=''''''+@obj+''''''''+crlf+ case relaxed when 1 then '''' else '' and [type]=''''''+@typ+'''''''' end+crlf+ '' and schema_id=schema_id(''''''+def_schema+'''''')''+crlf end+ '' )'' from fn__sym(),( select quotename(@schema) as q_schema, isnull(@schema,''dbo'')as def_schema, quotename(@parent) as q_parent, quotename(@obj) as q_obj, charindex(''|relaxed|'',''|''+isnull(@opt,'''')+''|'') as relaxed ) as params -- fn__script_drop' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__script_drop: -- ============================================================== fn__sysobjects select @ver=dbo.fn__script_sign('fn__sysobjects',1) if not @ver is null and @ver=131029.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__sysobjects') with nowait goto skip_fn__sysobjects end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sysobjects') with nowait if exists( select top 1 null from sys.objects where name='fn__sysobjects' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sysobjects] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131029\s.zaglio:moved from utility_old back to utility v:131001.1000\s.zaglio:refined indexes (pk,uq) r:130908\s.zaglio:adapted to fn__script_drop v:121202\s.zaglio:added parent_id,schema_id,drop_script,if_exists and tested r:121201\s.zaglio:added indexes and removed mssql2k compatibility v:121012\s.zaglio:added drop column v:110629\s.zaglio:list all sysobjects t:select * from fn__sysobjects(default,default,default) where typ in (''td'',''tr'') t:select * from fn__sysobjects(default,default,''if_exists'') where typ in (''fn'') t:select * from fn__sysobjects(default,default,''if_exists|relaxed'') where typ in (''fn'') t:sp__sysobjects_test */ CREATE function fn__sysobjects( @obj sysname, @schema_id int, @opt sysname -- drop_script: fill the drop script info -- if_exists: fill the [exists] column -- relaxed: passed to fn__script_drop ) returns @t table( id int, sch sysname null, obj sysname, typ varchar(2), -- in sys.objects is char(2) [drop] sysname null, parent sysname null, parent_typ varchar(2) null, -- in sys.objects is char(2) drop_script nvarchar(512) null, if_exists nvarchar(4000) null ) as begin declare @drop_script bit,@if_exists bit,@relaxed bit,@crlf nvarchar(4) select @obj=isnull(@obj,''%''),@crlf=crlf from fn__sym() if not @opt is null begin select @opt=''|''+@opt+''|'' select @drop_script=charindex(''|drop_script|'',@opt), @if_exists=charindex(''|if_exists|'',@opt), @relaxed=charindex(''|relaxed|'',@opt) end else select @drop_script=0,@if_exists=0 /* AF = funzione di aggregazione (CLR) C = vincolo CHECK D = DEFAULT (vincolo o valore autonomo) F = vincolo FOREIGN KEY FN = funzione scalare SQL FS = Funzione scalare di assembly (CLR) FT = funzione valutata a livello di tabella assembly (CLR) IF = funzione SQL inline valutata a livello di tabella IT = tabella interna P = Stored procedure SQL PC = Stored procedure di assembly (CLR) PG = Guida di piano PK = vincolo PRIMARY KEY R = regola (tipo obsoleto, autonoma) RF = procedura-filtro-replica S = tabella di base di sistema SN = sinonimo SQ = coda di servizio TA = trigger DML assembly (CLR) TF = funzione valutata a livello di tabella SQL TR = trigger DML SQL TT = tipo tabella U = tabella (definita dall''utente) UQ = vincolo UNIQUE V = vista X = stored procedure estesa */ insert @t(id,sch,obj,typ,[drop],parent,parent_typ) -- declare @schema_id int,@obj sysname select @obj=''%'' select o.object_id,s.name,o.[name],o.[type], case when o.[type] = ''U'' then ''table'' when o.[type] = ''SN'' then ''synonym'' when o.[type] = ''P'' then ''proc'' when o.[type] = ''V'' then ''view'' when o.[type] = ''TR'' then ''trigger'' when o.[type] in (''FN'',''FS'',''FT'',''IF'',''TF'') then ''function'' when o.[type] = ''D'' then ''constraint '' when o.[type] in (''PK'',''UQ'',''F'') then ''index '' else ''#!unktype '' end, p.name,p.[type] -- select top 10 * from sys.objects o left join sys.objects p on o.parent_object_id=p.object_id join sys.schemas s on o.schema_id=s.schema_id where not o.type in (''s''/*system*/,''tr''/*trigger are in sys.triggers*/) and o.name like @obj and (@schema_id is null or @schema_id=o.[schema_id]) union -- db trigger select t.object_id,null,t.name, case t.parent_id when 0 then ''TD'' else ''TR'' end, ''trigger'',p.name,p.[type] -- select * from sys.triggers t left join sys.objects p on t.parent_id=p.object_id where t.is_ms_shipped=0 and t.name like @obj union select index_id,null,i.name, case when is_primary_key=1 then ''PK'' when is_unique=1 then ''UQ'' else ''IX'' end, ''index'',p.name,p.[type] -- select top 10 * from sys.indexes i join sys.objects p on i.object_id=p.object_id join sys.schemas s on p.schema_id=s.schema_id where 0 in (i.is_primary_key,i.is_unique) and (p.type!=''s''/* or @sys=1*/) and i.name like @obj -- heep excluded because null name /* if @if_exists=1 update @t set [exists]=''if exists(''+@crlf +'' select top 1 null from ''+location +'' where name=''''''+obj+'''''''' +case */ if @drop_script=1 or @if_exists=1 update @t set drop_Script=case @drop_script when 0 then null else f.drop_script end, if_exists=case @if_exists when 0 then '''' else f.if_exists end from @t t cross apply fn__script_drop(t.obj,typ,sch,parent,case @relaxed when 1 then ''relaxed'' else null end) f return end -- fn__sysobjects' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sysobjects: -- ========================================================== fn__script_sysobjs select @ver=dbo.fn__script_sign('fn__script_sysobjs',1) if not @ver is null and @ver=131006.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__script_sysobjs') with nowait goto skip_fn__script_sysobjs end raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_sysobjs') with nowait if exists( select top 1 null from sys.objects where name='fn__script_sysobjs' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_sysobjs] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:131006\s.zaglio: adapted to change of flags.svr->flags.srv v:130926.1000,130217\s.zaglio:script_%;added enums(517) v:121031\s.zaglio:added script_act v:120517\s.zaglio:removed from core group v:120516.1900\s.zaglio: merged fn__script_events d:120516\s.zaglio: fn__script_events v:120504\s.zaglio: last change v:110620\s.zaglio: added typ field v:110527\s.zaglio: added new objs v:110510\s.zaglio: lists system objects t:select * from fn__script_sysobjs(default) t:select * from fn__script_sysobjs((select obj from tids)) t:select * from fn__script_sysobjs((select ev from tids)) */ CREATE function fn__script_sysobjs(@tid tinyint) returns @objs table ( tid tinyint, id int primary key, rid int, flags smallint, cod sysname ) as begin -- see entire list in -- ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.it/udb9/html/fb2a7bd0-2347-488c-bb75-734098050c7c.htm -- http://msdn.microsoft.com/it-it/library/ms179503%28v=sql.105%29.aspx declare @srv smallint,@db smallint,@tsrv smallint,@tdb smallint, @ts smallint,@tx smallint,@tt smallint,@tmask smallint, @ev tinyint, @obj tinyint, @grp tinyint select top 1 -- events @srv=srv|ddl, @db=db|ddl, @tsrv=[type]|srv|ddl, @tdb=[type]|db, -- sys.objects @ts=[sys], @tx=[exclude], @tt=[tmp] from flags select top 1 @ev=ev, @obj=obj, @grp=grp from tids if @tid is null insert @objs( tid, id, rid, flags, cod) select @grp, 500, null, @tmask, ''sys.objects'' if @tid is null or @tid=@obj insert @objs( tid, id, rid, flags, cod) select @obj, 501, 500, @ts, ''log'' union select @obj, 502, 500, @ts, ''cfg'' union select @obj, 503, 500, @ts, ''obj'' union select @obj, 504, 500, @tt, ''tmp'' union select @obj, 505, 500, @ts, ''ids'' union select @obj, 506, 500, @ts, ''lng'' union select @obj, 507, 500, @tx, ''dtproperties'' union select @obj, 508, 500, @tt, ''tst'' union select @obj, 509, 500, @tt, ''bak'' union select @obj, 510, 500, @ts, ''flags'' union select @obj, 511, 500, @ts, ''tids'' union select @obj, 512, 500, @ts, ''log_ddl'' union select @obj, 513, 500, @ts, ''tid'' union select @obj, 514, 500, @ts, ''flg'' union select @obj, 515, 500, @ts, ''iof'' union select @obj, 516, 500, @ts, ''script_%'' union select @obj, 517, 500, @ts, ''enums'' union select @obj, 518, 500, @ts, ''act'' -- events if @tid is null or @tid=@ev insert @objs( tid, id, rid, flags, cod) select @ev, 010, null, @tsrv, ''DDL_SERVER_LEVEL_EVENTS'' union select @ev, 011, 010, @srv, ''create_database'' union select @ev, 012, 010, @srv, ''alter_database'' union select @ev, 013, 010, @srv, ''drop_database'' union select @ev, 070, 010, @tdb, ''DDL_DATABASE_LEVEL_EVENTS'' union select @ev, 080, 070, @tdb, ''DDL_TABLE_VIEW_EVENTS'' union select @ev, 090, 080, @tdb, ''DDL_TABLE_EVENTS'' union select @ev, 091, 090, @db, ''create_table'' union select @ev, 092, 090, @db, ''alter_table'' union select @ev, 093, 090, @db, ''drop_table'' union select @ev, 100, 080, @tdb, ''DDL_TABLE_EVENTS'' union select @ev, 101, 100, @db, ''create_view'' union select @ev, 102, 100, @db, ''alter_view'' union select @ev, 103, 100, @db, ''drop_view'' union select @ev, 110, 080, @tdb, ''DDL_INDEX_EVENTS'' union select @ev, 111, 110, @db, ''create_index'' union select @ev, 112, 110, @db, ''alter_index'' union select @ev, 113, 110, @db, ''drop_index'' union select @ev, 114, 110, @db, ''create_xml_index'' union select @ev, 130, 070, @tdb, ''DDL_SYNONYM_EVENTS'' union select @ev, 131, 130, @db, ''create_synonym'' union select @ev, 132, 130, @db, ''drop_synonym'' union select @ev, 140, 070, @tdb, ''DDL_FUNCTION_EVENTS'' union select @ev, 141, 140, @db, ''create_function'' union select @ev, 142, 140, @db, ''alter_function'' union select @ev, 143, 140, @db, ''drop_function'' union select @ev, 150, 070, @tdb, ''DDL_PROCEDURE_EVENTS'' union select @ev, 151, 150, @db, ''create_procedure'' union select @ev, 152, 150, @db, ''alter_procedure'' union select @ev, 153, 150, @db, ''drop_procedure'' union select @ev, 160, 070, @tdb, ''DDL_TRIGGER_EVENTS'' union select @ev, 161, 160, @db, ''create_trigger'' union select @ev, 162, 160, @db, ''alter_trigger'' union select @ev, 163, 160, @db, ''drop_trigger'' union select @ev, 170, 070, @tdb, ''DDL_TYPE_EVENTS'' union select @ev, 171, 170, @db, ''create_type'' union select @ev, 173, 170, @db, ''drop_type'' union select @ev, 200, 070, @tdb, ''DDL_DATABASE_SECURITY_EVENTS'' union select @ev, 220, 200, @tdb, ''DDL_USER_EVENTS'' union select @ev, 221, 220, @db, ''create_user'' union select @ev, 222, 220, @db, ''alter_user'' union select @ev, 223, 220, @db, ''drop_user'' union select @ev, 230, 200, @tdb, ''DDL_ROLE_EVENTS'' union select @ev, 231, 230, @db, ''create_role'' union select @ev, 232, 230, @db, ''alter_role'' union select @ev, 233, 230, @db, ''drop_role'' union select @ev, 250, 200, @tdb, ''DDL_SCHEMA_EVENTS'' union select @ev, 251, 250, @db, ''create_schema'' union select @ev, 252, 250, @db, ''alter_schema'' union select @ev, 253, 250, @db, ''drop_schema'' union select @ev, 260, 200, @tdb, ''DDL_GDR_DATABASE_EVENTS'' union select @ev, 261, 260, @db, ''grant_database'' union select @ev, 262, 260, @db, ''deny_database'' union select @ev, 263, 260, @db, ''revoke_database'' -- special data events union select @ev, 270, null, @tdb, ''DML_EVENTS'' union select @ev, 271, 270, @tdb, ''insert_data'' -- special control events union select @ev, 280, null, @tdb, ''CTRL_EVENTS'' union select @ev, 281, 280, @tdb, ''group_objects'' return end -- fn__script_sysobjs' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__script_sysobjs: -- ============================================================ fn__str_distance select @ver=dbo.fn__script_sign('fn__str_distance',1) if not @ver is null and @ver=121007.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'fn__str_distance') with nowait goto skip_fn__str_distance end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_distance') with nowait if exists( select top 1 null from sys.objects where name='fn__str_distance' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_distance] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:121007\s.zaglio: a remake (see inside code comments) v:081130\S.Zaglio: Levenshtein algo. Originally from http://www.marcopipino.it/sql/levenshtein.php t: print dbo.fn__str_distance(''stefano'',''stefania'',default) -- 1.5 print dbo.fn__str_distance(''stefano'',''giovanni'',default) -- 7.5 print dbo.fn__str_distance(''dal-7134ab1'',''dal=7134ab1'',default) -- 1 print dbo.fn__str_distance(''dal-7134ab1'',''dal7134ab1'',default) -- 1.5 print dbo.fn__str_distance(''dal-7134ab1'',''dal7134ab11'',default) -- 2 print dbo.fn__str_distance(''C.SO UMBERTO I'',''PIAZZA UMBERTO I'',10) -- 6 print dbo.fn__str_distance(''C.SO UMBERTO I'',''PIAZZA UMBERTO I'',40) -- 5 */ CREATE function dbo.fn__str_distance( @s1 nvarchar(255), @s2 nvarchar(255), @maxoffset int -- default is 5 ) returns float as begin /* this is the choose after some test between 5 fn over 9900 streets: 1. the original from http://www.marcopipino.it/sql/levenshtein.php 4m 45s 476ms 2. LEVENSHTEIN(@s,@t) 41s 893ms 3. edit_distance_within 8s 70ms 4. Sift3distance2 956ms 5. udfDamerauLevenshteinLim 10s 166ms Maybe the 5 can be better but I have no time for a deep test The Sift3distance2 is more accurate in some cases: VIA DEI FRENTANI VIA DEI VESTINI 7,5 vs 4 in all other fn and less accurate in some other cases: C.SO UMBERTO I PIAZZA UMBERTO I 15 vs 6 at offset 35 */ declare @s1len int,@s2len int select @s1len=len(isnull(@s1,'''')),@s2len=len(isnull(@s2,'''')) if @s1len=0 return @s2len else if @s2len=0 return @s1len if isnull(@maxoffset,0)=0 set @maxoffset=5 declare @currpos int,@matchcnt int,@wrkpos int, @s1offset int,@s1char varchar,@s1pos int,@s1dist int, @s2offset int,@s2char varchar,@s2pos int,@s2dist int select @s1offset=0,@s2offset=0,@matchcnt=0,@currpos=0 while(@currpos+@s1offset<@s1len and @currpos+@s2offset<@s2len) begin set @wrkpos=@currpos+1 if(substring(@s1,@wrkpos+@s1offset,1)=substring(@s2,@wrkpos+@s2offset,1)) set @matchcnt=@matchcnt+1 else begin set @s1offset=0 set @s2offset=0 select @s1char=substring(@s1,@wrkpos,1), @s2char=substring(@s2,@wrkpos,1) select @s1pos=charindex(@s2char,@s1,@wrkpos)-1, @s2pos=charindex(@s1char,@s2,@wrkpos)-1 select @s1dist=@s1pos-@currpos,@s2dist=@s2pos-@currpos if(@s1pos>0 and (@s1dist<=@s2dist or @s2pos<1) and @s1dist<@maxoffset) set @s1offset=(@s1pos-@wrkpos)+1 else if(@s2pos>0 and (@s2dist<@s1dist or @s1pos<1) and @s2dist<@maxoffset) set @s2offset=(@s2pos-@wrkpos)+1 end set @currpos=@currpos+1 end return (@s1len+@s2len)/2.0-@matchcnt end -- fn__str_distance' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_distance: -- =============================================================== sp__deprecate select @ver=dbo.fn__script_sign('sp__deprecate',1) if not @ver is null and @ver=130903.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'sp__deprecate') with nowait goto skip_sp__deprecate end raiserror('re-creating "%s.%s"',10,1,@db,'sp__deprecate') with nowait if exists( select top 1 null from sys.objects where name='sp__deprecate' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__deprecate] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script todo:manage version v:130903\s.zaglio:renamed from sp__deprecated v:121004.1614\s.zaglio: used to delete D tagged objects objects t:sp__deprecated ''test_scripting'' */ CREATE proc sp__deprecate @obj sysname = null, @ver numeric(10,4) = null as begin set nocount on declare @proc sysname, @err int, @ret int, @type sysname,@sql nvarchar(4000) select @proc=object_name(@@procid),@err=0,@ret=0 if isnull(@obj,'''')='''' goto help select @type=[drop] from fn__sysobjects(@obj,default,default) if @type is null return @ret -- select distinct [type] from sys.objects select @sql=''drop ''+@type+'' ''+quotename(@obj) if not @sql is null begin raiserror(''drop deprecated "%s"(%s)'',10,1,@obj,@type) with nowait exec(@sql) end return @ret help: exec sp__usage @proc,'' Scope drop deprecated object is exists (fast and smaller version of sp__drop) '' return -1 end -- proc sp__deprecated' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__deprecate: -- =========================================================== sp__script_update select @ver=dbo.fn__script_sign('sp__script_update',1) if not @ver is null and @ver=140204.0000 begin raiserror('skipped "%s.%s" because is the same', 10,1,@db,'sp__script_update') with nowait goto skip_sp__script_update end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_update') with nowait if exists( select top 1 null from sys.objects where name='sp__script_update' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_update] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:test,conflict,difference,upgrade v:140204\s.zaglio:better error management v:140116.1100\s.zaglio:added better compare output, help and use of context info v:140108.1518\s.zaglio:set of default @tcc to 10 and added ovr option v:131216.1500\s.zaglio:added STRICT option and correct a bug near compare v:131215\s.zaglio:refactor and added relaxed check of ver without .hhmm v:131210.1000\s.zaglio:compare for @tcc common comments and overwrite dst v:131103\s.zaglio:a bug when pair conflict\common (conflict===update) v:131018.1210\s.zaglio:added SD option and removed initial blnk lines v:130908.0100\s.zaglio:converted to update utility r:121006\s.zaglio:replacing script header template t:sp__script_update_test @dbg=2 */ CREATE proc sp__script_update @src nvarchar(max) = null, @db sysname = null, @tcc int = null, @opt sysname = null, @dbg int=0 as begin try set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000),@err_sev int-- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- ============================================================== declaration == declare -- object and its type @obj sysname,@t_type nvarchar(4), @sch sysname,@params sysname, -- used by sp_executesql -- new object info @pcmd int, -- create/alter position @cmd sysname, -- create/alter @otype sysname, -- proc/func/... @t_obj_id int, -- target object id -- local vars @tag char, @s_obj sysname, -- sub object commodity @ver sysname, -- version commodity @sql nvarchar(max), -- sql commodity @dst nvarchar(max), -- destination/target src @drop nvarchar(4000), @crlf nvarchar(2), @sp__update_log sysname, @sp__update_log_id int, @threshold_last_cmt tinyint, -- see below @cmts_min_distance tinyint, -- see below @n int,@m int, -- options @test bit,@sd bit,@strict bit,@ovr bit, -- status @sts char, @st_common tinyint, @st_conflict tinyint, @st_update tinyint, -- target(correct) update @st_left_update tinyint, -- new il order @st_err tinyint, @st_unk tinyint, @end_declare bit declare @nfo table ( tag varchar(4),row smallint, val1 sysname,val2 sysname,val3 sysname ) declare @cmprs table( row int, b_ver numeric(10,4), m_ver numeric(10,4), diff float, t_row smallint,n_row smallint, t_ver numeric(10,4) null,n_ver numeric(10,4) null, t_aut sysname null,n_aut sysname null, t_cmt nvarchar(512) null,n_cmt nvarchar(512) null, sts tinyint null ) -- target or current object info declare @dst_nfo table( row smallint not null, ver numeric(10,4) null, aut nvarchar(4000) null, cmt nvarchar(4000) null, hhmm bit not null, tick smallint, -- sub sequence when doubled version lrow smallint ) -- source or new object info declare @src_nfo table( row smallint not null, ver numeric(10,4) null, aut nvarchar(4000) null, cmt nvarchar(4000) null, hhmm bit not null, tick smallint, -- sub sequence when doubled version diff float, -- distance between dst.val3 and src.val3 lrow smallint ) -- =========================================================== initialization == if @db is null select @db=db_name() select @tcc=isnull(@tcc,10), -- this values is from experience and must -- be modified only if very sure @threshold_last_cmt = 3, -- same above consideration @cmts_min_distance = 4, -- same of above @crlf=crlf, @test=charindex(''|test|'',@opt), @sd=charindex(''|sd|'',@opt), @strict=charindex(''|strict|'',@opt), @ovr=charindex(''|ovr|'',@opt)|dbo.fn__context_info(@proc+'':ovr''), @st_unk=0, @st_common=1, @st_update=2, @st_conflict=3, @st_left_update=4, @st_err=5 from fn__sym() -- ======================================================== second params chk == if nullif(@src,'''') is null goto help -- =============================================================== #tbls init == select @sp__update_log_id=isnull(object_id(''tempdb..#sp_update_log''),0) if @sp__update_log_id=0 -- if not defined outside begin exec(''create proc #sp__update_log @obj sysname, @st char, @msg nvarchar(2000) = null as declare @sev int select @sev=10 if not object_id(''''tempdb..#update_log'''') is null insert #update_log(obj,msg,sts) select @obj,@msg,@st -- Updated,New,Same,Older,Conflict,Error select @msg=case @st when ''''E'''' then @msg when ''''U'''' then ''''updated-re-created'''' when ''''N'''' then ''''new-created'''' when ''''S'''' then ''''same-not replaced'''' when ''''O'''' then ''''older-not replaced'''' when ''''C'''' then ''''conflict''''+ isnull('''':''''+@msg,'''''''') end if @st=''''C'''' select @sev=11 if @st=''''E'''' select @sev=16 select @msg=@obj+'''':''''+@msg raiserror(@msg,@sev,1) '') end select @sp__update_log=''#sp__update_log'' -- ===================================================================== body == /* get object name proc func view tabl syno */ if @dbg>0 exec sp__printf ''-- %s: debugging level:%d'',@proc,@dbg -- ================================================= get info from new script == -- remove initial blank lines while left(@src,1) like ''[%''+@crlf+''%]'' select @src=stuff(@src,1,1,'''') insert @nfo select tag,row,val1,val2,val3 from fn__script_info_tags(@src,''ad#'',default) if @dbg>1 select ''new'' [?],* from @nfo select @obj=parsename(val3,1),@pcmd=row,@cmd=val1,@otype=val2 from @nfo where tag=''#'' if @cmd!=''create'' raiserror(''command "%s" not managed'',16,1,@cmd) if not @otype in (''proc'',''procedure'',''func'',''function'',''view'',''trigger'') begin select @err_msg=''object type "''+@otype+''" not managed'' exec @sp__update_log @obj,''E'',@err_msg end -- ============================================== get info from target object == -- target object cannot be locked, so do not use (nolock) select @dst='' use [%db%] select @id=o.object_id, @type=o.[type],@code=m.definition,@sch=sch from ( select object_id,name,type,object_schema_name(object_id) sch from sys.objects where name="%obj%" union select object_id,name,type,object_schema_name(object_id) sch from sys.triggers where name="%obj%" ) o join sys.all_sql_modules m on o.object_id=m.object_id '' exec sp__str_replace @dst out,''"|%db%|%obj%'','''''''',@db,@obj select @params=N''@id int out,@type nvarchar(4) out,@code nvarchar(max) out,'' +N''@sch sysname out'' exec sp_executesql @dst, @params, @id=@t_obj_id out,@type=@t_type out,@code=@dst out,@sch=@sch out if @t_obj_id is null begin select @sts=''N'' -- new goto do_action end -- ================================================================== compare == if @ovr=1 begin exec sp__printf ''-- OVERRIDE option enabled'' select @sts=''U'' goto do_action end begin try insert into @dst_nfo(ver,aut,cmt,row,hhmm,tick,lrow) select cast(ver as numeric(10,4)),aut,cmt, row,hhmm, row_number() over (partition by ver,aut order by ver,row desc)-1 as tick, row_number() over (order by row)-1 as lrow from ( -- convert aaaammgg.hhmm to aammgg.hhmm select case when val1<999999 then val1 else val1-cast(val1/1000000 as int)*1000000 end as ver,val2 as aut,val3 as cmt,row,hhmm from ( select cast(val1 as numeric(12,4)) as val1,val2,val3, row,charindex(''.'',val1) as hhmm from fn__script_info_tags(@dst,''rv'',default) where isnumeric(val1)=1 -- skip non coerent comments ) nfo ) nfo order by row select @m=@@rowcount insert into @src_nfo(ver,aut,cmt,row,hhmm,tick,lrow) select cast(ver as numeric(10,4)),aut,cmt, row,hhmm, row_number() over (partition by ver,aut order by ver,row desc)-1 as tick, row_number() over (order by row)-1 as lrow from ( -- convert aaammgg.hhmm to aammgg.hhmm select case when val1<999999 then val1 else val1-cast(val1/1000000 as int)*1000000 end as ver,val2 as aut,val3 as cmt,row,hhmm from ( select cast(val1 as numeric(12,4)) as val1,val2,val3, row,charindex(''.'',val1) as hhmm from fn__script_info_tags(@src,''rv'',default) where isnumeric(val1)=1 -- skip non coerent comments ) nfo ) nfo order by row select @n=@@rowcount if @n=0 exec @sp__update_log @obj,''E'',''cannot identify source properties'' if @m<2 -- if destination has not comments begin select @sts=''U'' goto do_action end -- some automatic adjustements to prevent user''s fortuity if @strict=0 begin -- correct dates with .0000 binding to comment update @src_nfo set ver=ver+tick/10000.0 where hhmm=0 update @dst_nfo set ver=ver+tick/10000.0 where hhmm=0 -- adjust similar comments update src set diff=dbo.fn__str_distance(src.cmt,dst.cmt,default) from @src_nfo src join @dst_nfo dst on src.ver=dst.ver and src.aut=dst.aut if @dbg>2 begin select ''@src_info'' tbl,* from @src_nfo order by row select ''@dst_info'' tbl,* from @dst_nfo order by row end end -- relaxed or strict=0 ;with compare as ( select isnull(t_ver,n_ver) m_ver,* from ( select t.row as t_row, n.row as n_row, t.ver as t_ver, t.aut as t_aut, t.cmt as t_cmt, n.ver as n_ver, n.aut as n_aut, n.cmt as n_cmt, case when n.lrow=0 and t.lrow=0 -- only last row and n.ver-t.ver between 0 and 1 -- same date and n.aut=t.aut -- same author and dbo.fn__str_distance(n.cmt,t.cmt,default) < len(n.cmt)/@cmts_min_distance then 0 else dbo.fn__str_distance(n.cmt,t.cmt,default) end as diff from @dst_nfo as t -- target/current version full join @src_nfo as n -- source/new version on t.ver=n.ver and t.aut=n.aut -- aligned by datetime and author or (-- or is a last ... n.lrow=0 and t.lrow=0 -- ... daily change ... and n.ver-t.ver between 0 and 1 -- ... by same user ... and n.aut=t.aut -- ... with a small change and dbo.fn__str_distance(n.cmt,t.cmt,default) < len(n.cmt)/@cmts_min_distance ) ) a ), -- find 1st common base ver base_ver(b_ver) as ( -- select the older select top 1 b_ver from ( -- take last 4 common comments select top (@tcc) t_ver as b_ver from compare where t_ver=n_ver order by m_ver desc ) commons order by b_Ver ) insert into @cmprs( row,b_ver,m_ver,diff,t_row,n_row,t_ver,n_ver,t_aut,n_aut,t_cmt,n_cmt,sts ) select row_number() over(order by m_ver desc), (select top 1 b_ver from base_ver) as b_ver, m_ver,diff,t_row,n_row,t_ver,n_ver,t_aut,n_aut,t_cmt,n_cmt, case -- do not change order of whens when (not n_cmt is null and t_cmt is null) or (diff=0 and t_cmt!=n_cmt) then @st_update when (n_cmt is null and not t_cmt is null) then @st_left_update when (diff<=@cmts_min_distance) then @st_common when (diff>@cmts_min_distance) then @st_conflict else @st_err end sts from compare where m_ver>=(select top 1 b_ver from base_ver) order by m_ver desc -- merged version end try begin catch -- possible fn__script_info_tags error if @dbg>1 exec sp__printsql @dst select @err_msg=left(error_procedure(),len(@sp__update_log)) if @err_msg!=@sp__update_log select @err_msg=''SP inside error at line ''+cast(error_line() as sysname) +'' maybe near fn__script_info_tags; check header with @dbg=2'' else select @err_msg=error_message() select @err_sev=error_severity() raiserror(@err_msg,@err_sev,1) end catch -- complete unknown situations update @cmprs set sts=@st_unk where sts is null -- =================================================================== checks == if @dbg>1 begin select @db as db,''@cmprs'' tbl,*, case sts when @st_common then ''common'' when @st_update then ''update'' when @st_conflict then ''conflict'' when @st_err then ''algorithm missing error'' when @st_unk then ''algorithm unknown error'' when @st_left_update then ''left_update'' end as [status] from @cmprs end if exists(select top 1 null from @cmprs where sts in (@st_err,@st_unk)) exec @sp__update_log @obj,''E'',''algorithm'' -- if no common base comment if not exists(select top 1 null from @cmprs where sts=@st_common) and (select count(*) from @dst_nfo)>0 -- 131210\s.zaglio exec @sp__update_log @obj,''E'',''too much different releases'' -- overwrite targets that do not has comments (without header) select @sts='''' declare @mark_a int,@mark_b int select @mark_a=null,@mark_b=null select top 1 @mark_a=case when a.sts=@st_conflict then a.n_row else b.n_row end from @cmprs a left join @cmprs b on b.row=a.row+1 where 1=0 -- (a.sts=@st_common and isnull(b.sts,@st_common)=@st_update) or (a.sts=@st_common and isnull(b.sts,@st_common)=@st_left_update) or (a.sts=@st_update and isnull(b.sts,@st_common)=@st_left_update) or (a.sts=@st_conflict) order by a.row if @@rowcount>0 select @sts=''C'',@mark_b=@mark_a -- if same or small comment difference if @sts='''' and not exists(select top 1 null from @cmprs where sts!=@st_common) begin if exists(select top 1 null from @cmprs where t_cmt!=n_cmt) select @sts=''U'' else select @sts=''S'' end -- if newer if @sts='''' and exists ( select top 1 null from @cmprs c where c.row=1 and c.sts=@st_update and t_cmt is null ) select @sts=''U'' -- if newer (for last,quick,small modification) if @sts='''' and not exists ( select top 1 null from @cmprs c -- where c.row=1 and c.sts=@st_update and not t_cmt is null and n_ver>=t_ver where not c.sts in (@st_update,@st_common) ) select @sts=''U'' -- older if @sts='''' select @sts=''O'' -- if @sts='''' raiserror(''inside error, unmanaged condition'',16,1) -- ============================================ show result status of compare == do_action: if @dbg>1 select @sts as ''------------------- result_action -------------------'' -- check for aliases and deprecates declare cs cursor local for select tag,val1 as ver,val3 as obj from @nfo where @sts!=''C'' -- <<<<<<<<<<<<< NB >>>>>>>>>>> and tag in (''a'',''d'') order by val1 open cs while 1=1 begin fetch next from cs into @tag,@ver,@s_obj if @@fetch_status!=0 break select @sql=''use ''+quotename(@db)+@crlf if @tag=''D'' select @sql=@sql+''exec sp__deprecate ''''''+@s_obj+'''''',''+@ver if @tag=''A'' select @sql=@sql+''exec sp__aliases ''''''+@s_obj+'''''',@of=''''''+@obj+'''''''' begin try if @test=0 exec(@sql) end try begin catch select @err_msg=error_message() exec @sp__update_log @obj,''E'',@err_msg end catch end -- cursor cs close cs deallocate cs if @sts in (''O'',''S'') -- older,same begin exec @sp__update_log @obj,@sts goto dispose end if @sts=''C'' -- conflict begin if @sd=1 if @test=1 -- show difference of lines select ''diff'' tbl,isnull(a.lno,b.lno) lno,@db as db,@obj as obj, isnull(b.line,'''') as [current(A)], isnull(a.line,'''') as [new(B)] from fn__ntext_to_lines(@src,0) a full outer join fn__ntext_to_lines(@dst,0) b on a.line=b.line and abs(a.lno-b.lno)<10 order by isnull(a.lno,b.lno) else -- show the two sequence of lines begin select @sql='' select isnull(b.line,'''''''') as [''+@db+''.''+@obj+''], isnull(a.line,'''''''') as [new code], case when a.lno between @mark_a and @mark_b then ''''<<'''' else '''''''' end [??] from fn__ntext_to_lines(@src,0) a full outer join fn__ntext_to_lines(@dst,0) b on a.lno=b.lno order by isnull(a.lno,b.lno)'' exec sp_executesql @sql, N''@src nvarchar(max),@dst nvarchar(max),@mark_a int,@mark_b int'', @src=@src,@dst=@dst,@mark_a=@mark_a,@mark_b=@mark_b end -- sd option exec @sp__update_log @obj,@sts -- raiserror 11 end -- conflict -- ================================================================ do update == if @sts!=''N'' select @drop=if_exists+@crlf+'' ''+drop_script from fn__script_drop(@obj,@t_type,@sch,default,''relaxed'') -- remove initial crlf while left(@src,len(@crlf))=@crlf select @src=stuff(@src,1,len(@crlf),'''') select @src=''use ''+quotename(@db)+@crlf +''begin try''+@crlf +''begin tran sp__script_update''+@crlf +isnull(@drop+@crlf,'''') +''exec(''''''+replace(@src,'''''''','''''''''''')+'''''')''+@crlf +''commit tran sp__script_update''+@crlf +''end try''+@crlf +''begin catch''+@crlf +''rollback tran sp__script_update''+@crlf +''declare @m nvarchar(2000),@s int''+@crlf +''select @m=error_message(),@s=error_severity()''+@crlf +''raiserror(@m,@s,1)''+@crlf +''end catch'' begin try -- todo: encose in trans and manage nested if @dbg>0 exec sp__printsql @src if @test=0 exec(@src) -- ================================================================ run SETUP == if @obj like ''%[_]setup'' begin if @dbg>0 exec sp__printf ''-- will be executed as setup'' else begin if @test=0 exec (''exec ''+@obj+'',@opt=''''run'''''') end end exec @sp__update_log @obj,@sts end try begin catch select @err_msg=error_message(),@err_sev=error_severity() exec @sp__update_log @obj,''E'',@err_msg end catch -- ================================================================== dispose == dispose: if @sp__update_log_id=0 drop proc #sp__update_log -- if it come from outside goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope analyze the script and update of relative object in the specified db Notes - be careful with grouped comments (left the lasts as single) - actually drop and re-create the object because too difficult understand when sub-type deeply change (example TF to IF) - for a complete list of test cases see sp__script_update_test - tag D is performed (sp__deprecate @db.@obj,@ver,@aut ) - if the name of object end with "_setup", the sp will be executed with @opt=run (be sure that the sp of setup must run more times) - commonly this util will be used by your deploy engine as: - create deploy log - create #update log - call sp for each new object - save #update log into deploy log - eventually repeat script 3 times (for dependencies) - send email with report or other - version and comments are used to check effective code progression - the possible conditions are: - regular (right) upgrade (only new comments on right side) - nothing to do (only common comments) - conflict (one or more comments on the left) - upgrade of merge or minor update (last comment changed on the right) - older (less comments in the new script) id current new status -- ----------------------- --------------------------- ---------- 01 yymmd3\auth0:comment3 yymmd3.hhmm\auth0:comment3.x merged or reviewd 02 (not present) yymmd2\auth1:comment2 new line 03 yymmd1\auth2:comment1 (not present) conflict or newer 04 yymmd0\authX:commentXXX yymmd0\auth3:commentYYY conflict 05 yymmd0\auth3:comment0 yymmd0\auth3:comment0 last common - lasts 10 comments are taken from each side and compared - if "current" has more comments than "new", means that current is newer - if 1st comment change a bit in the comment and/or in the time, is a small revision Todo - if the new script present a "a"(sp__alias @db.obj,@obj),"j" tag, "t" tag Parameters [param] [desc] #update_log (optional) store update status create table #update_log( id int identity, dt datetime default(getdate()) not null, who sysname default system_user+''''@''''+ isnull(host_name(),''''???''''), obj sysname, sts char, -- Updated,New,Same,Older,Conflict,Error msg nvarchar(2000) ) anyway a raiserror 11 is given @src source script with "new" version @db target db (default is local), @tcc top common comments to check from history (default:%p1%) useful when a bug fix is integrated with same comment in a future version where another user had previusly added a new feature (see example in notes) @opt options test do not update, test only the possibility (no conflicts) sd show a two column table with two codes, to simplify cut and paste into Kdiff or similar when in conflict strict do not replace missed .hhmm ovr force override (update or create) the local OVR is overridden bye a global OVR, enabled with: sp__context_info ''''sp__script_update:ovr'''' @dbg 1=base info 2=compare table 3=middle and campare table Examples sp__script_update_test 1,@dbg=1 '',@p1=@tcc select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" if @sp__update_log_id=0 and not object_id(''tempdb..#sp__update_log'') is null drop proc #sp__update_log -- exec @ret=sp__err @cod=@proc,@opt=''ex'' declare @e_msg nvarchar(4000),@e_sev int -- this come always from #sp select @e_msg=error_message(),@e_sev=error_severity() raiserror(@e_msg,@e_sev,1) return @ret end catch -- proc sp__script_update' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_update: -- ########################## -- ## -- ## remove deprecated -- ## -- ######################################################## exec sp__deprecate 'sp__release',120823 exec sp__deprecate 'sp__objs',120821 exec sp__deprecate 'fn__crc32_table',120516 exec sp__deprecate 'fn__script_events',120516 exec sp__deprecate 'sp__config',131117 exec sp__deprecate 'fn__crc16_tbl',130202 exec sp__deprecate 'fn__crc32_tbl',130202 exec sp__deprecate 'fn__flds_row',100228 exec sp__deprecate 'fn__parseurl',130906 exec sp__deprecate 'fn__parsefilename',120123 exec sp__deprecate 'fn__object_id',130922 exec sp__deprecate 'sp__clientip',130517 exec sp__deprecate 'sp__serverip',130517 exec sp__deprecate 'sp__parse_conn',130517 exec sp__deprecate 'fn__sql_simplify',120809 exec sp__deprecate 'fn__chk_str',121004 exec sp__deprecate 'fn__taxcode',130830 exec sp__deprecate 'fn__street',140127 exec sp__deprecate 'sp_info',140127 exec sp__deprecate 'sp_find',140103 exec sp__deprecate 'sp__parse',130806 exec sp__deprecate 'sp__parse_test',130806 exec sp__deprecate 'fn__flds_list',121003 exec sp__deprecate 'sp__flds_of',121003 exec sp__deprecate 'sp__search',121003 exec sp__deprecate 'sp__get_tmp',131208 exec sp__deprecate 'sp__maint_stats',130630 exec sp__deprecate 'sp__log_show',100314 exec sp__deprecate 'sp__log_search',100314 exec sp__deprecate 'sp__trace_search',100314 exec sp__deprecate 'sp__perf_top25',110926 exec sp__deprecate 'sp__util_profile',130630 exec sp__deprecate 'sp__util_sqltrace',130630 exec sp__deprecate 'sp__scropt',111027.1000 exec sp__deprecate 'sp__table_align',120727 exec sp__deprecate 'sp__script_copytable',120727 exec sp__deprecate 'sp__assembly',121027 exec sp__deprecate 'sp__script_vtable',120508 exec sp__deprecate 'sp__script_tofile',130824 exec sp__deprecate 'sp__script_info_tags_test_old',130519 exec sp__deprecate 'sp__script_copy',120910 exec sp__deprecate 'sp__util_ddl',120103 exec sp__deprecate 'sp__script_trace',110623 exec sp__deprecate 'sp__select',130521 exec sp__deprecate 'sp__checkout',130902 exec sp__deprecate 'sp__script_deploy',130902 exec sp__deprecate 'sp__script_svn_log',120823 exec sp__deprecate 'sp__web_get',121018 -- ########################## -- ## -- ## group objects -- ## -- ######################################################## -- =========================================================== sp__utility_setup select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__utility_setup',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140109.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__utility_setup') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__utility_setup') with nowait goto skip_sp__utility_setup end if @ver>140109.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__utility_setup') with nowait goto skip_sp__utility_setup end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__utility_setup') with nowait if exists( select top 1 null from sys.objects where name='sp__utility_setup' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__utility_setup] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140109.1000\s.zaglio:moved call of sp__job_test into sp__utility_setup_test v:140103\s.zaglio:add call of sp__job_test v:131223.1110\s.zaglio:log_ddl.svr->srv v:131212\s.zaglio:removed use of sp__printf v:131125\s.zaglio:moved here the update of log_ddl v:130922\s.zaglio:about cfg v:130830\s.zaglio:managed a problem of fn__find when fnd is wrong v:130828\s.zaglio:due difficult to understand clr status I changed strategy v:130730.1800\s.zaglio:removed test of 130606 because too generic; added synonym v:130606\s.zaglio:added test for use of old sp__printf v:130528\s.zaglio:tuned test about CLR v:121209\s.zaglio:added check for awe m.m. v:121031\s.zaglio:commented clr and modified assembly for 2.0x32 v:120920\s.zaglio:added opt run v:120907\s.zaglio:added script_act v:120824\s.zaglio:better 0 condition, removed sp__ dependencies d:120823\s.zaglio:sp__release d:120821\s.zaglio:sp__objs v:120724.1800\s.zaglio: create and upgrade objects t:sp__utility_setup ''run'' t:sp__utility_setup ''run|log_ddl'' */ CREATE proc [dbo].[sp__utility_setup] @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=isnull(''|''+@opt+''|'','''') -- ========================================================= param formal chk == if charindex(''|run|'',@opt)=0 goto help -- ============================================================== declaration == declare @upg_log_ddl bit, @begin bit,@end bit, -- called at begin of script or at end @tmp nvarchar(max), @sign sysname, @log_ddl bit -- =========================================================== initialization == select @log_ddl=charindex(''|log_ddl|'',@opt), @begin=charindex(''|begin|'',@opt), @end=charindex(''|end|'',@opt) -- ======================================================== second params chk == if @log_ddl=1 goto log_ddl -- ########################## -- ## -- ## begin -- ## -- ######################################################## -- ===================================================================== body == log_ddl: /* 131125\s.zaglio:moved here the upgrade of log_ddl because executed before a function like fn__script_trace that uses this table and that will fail on compilation */ if not object_id(''log_ddl'') is null begin -- ifolder version of utility or log_ddl if object_id(''fn__script_sign'') is null select @upg_log_ddl=1 else -- select dbo.fn__script_sign(''log_ddl_bak'',default) -- select dbo.fn__script_sign(''log_ddl'',default) if dbo.fn__script_sign(''log_ddl'',default)=1612475947 begin raiserror(''-- minor upgrade of log ddl'',10,1) exec sp_rename ''log_ddl.svr'' , ''srv'', ''column'' --> 1679584815 end if dbo.fn__script_sign(''log_ddl'',default)=1477379425 select @upg_log_ddl=1 if @upg_log_ddl=1 begin raiserror(''-- upgrading log_ddl'',10,1) if not object_id(''log_ddl_bak'') is null drop table log_ddl_bak select * into log_ddl_bak from log_ddl drop table log_ddl end end -- upgrade log_ddl -- drop table log_ddl if object_id(''log_ddl'') is null begin -- drop table LOG_DDL create table LOG_DDL( svr int, -- fast and simple merge group id int, tid tinyint, rid int, -- parent id (tsql->obj->db) | app->host\usr pid int, -- host\usr->db(rid) | app->...tsql... flags smallint, -- at least 0 skey as case when tid!=12 -- select code from tids then substring([txt],1,128) else null end, [key] int, -- crc32 of skey if tid!=code txt nvarchar(max) null, -- tsql ev smallint null, -- event rel int null, -- release dt datetime, -- at least getdate constraint PK_LOG_DDL primary key (id desc) ) -- drop index log_ddl.IX_LOG_DDL_KEY create index IX_LOG_DDL_KEY on log_ddl(tid,[key],dt desc) -- include (id) -- 100:13s:+21% include(id,svr,skey,rid) -- 100:4s:+28% -- select id from log_ddl where tid=2 and [key]=2 and skey=''test'' raiserror(''-- table log_ddl created'',10,1) end -- create table if @log_ddl=1 goto ret -- ====================================================================== cfg == -- select dbo.fn__script_sign(''cfg'',default) if not object_id(''cfg'') is null and dbo.fn__script_sign(''cfg'',default) in ( 1865897288.0000,2083733301.0000 ) begin print ''-- dropped old cfg '' drop table cfg end if object_id(''cfg'') is null begin create table [dbo].[cfg] ( [id] int not null identity(1,1) , [flags] smallint not null, [rid] int not null , [key] sysname collate Latin1_General_CI_AS not null , [val] sql_variant not null ) on [PRIMARY] alter table [dbo].[cfg] add constraint [pk_cfg] primary key clustered ( [id] DESC ) on [PRIMARY] create unique nonclustered index [ix_cfg] on [dbo].[cfg]( rid,[key] ) on [PRIMARY] select @sign=dbo.fn__script_sign(''cfg'',1) -- with idx print ''-- new cfg created with sign: ''+@sign end -- cfg else print ''-- cfg already exists'' -- update fnd table or view (has the same sign) if dbo.fn__script_sign(''fnd'',default)!=1649957971.0000 begin exec sp__drop ''fnd'' print ''-- fnd dropped'' end else begin -- test if fnd a view/synonym to a not existant table if not object_id(''fnd'') is null begin try exec(''declare @id int select top 0 @id=id from fnd'') print ''-- fnd of last version'' end try begin catch exec sp__drop ''fnd'' print ''-- fnd dropped because point to nothing'' end catch end if object_id(''script_act'') is null begin -- drop table script_act create table script_act( id int identity constraint pk_script_act primary key, rid int, -- crc32(@proc) pid int, -- crc32(@obj) idx int, -- execution order txt nvarchar(4000) ) create unique index ix_script_act_rid_pid on script_act(rid,pid) end -- script_act if object_id(''sp__trace'') is null and not object_id(''sp__log_trace'') is null begin print ''-- create synonym for sp__trace->sp__log_trace'' create synonym sp__trace for sp__log_trace end /* to check NET version xp_instance_regenumkeys ''HKEY_LOCAL_MACHINE'', ''Software\Microsoft\NET Framework Setup\NDP'' */ -- cause memory pressure this do not compile; must use AWE mode or have 64bit -- ########################## -- ## -- ## do not comment hex code, see sp__script, comment 121212 -- ## -- ######################################################## declare @asm varbinary(max) select @asm=0x\\ 4d5a90000300000004000000ffff0000b80000000000000040000000000000000000000000000000000000000000000000000000000000000000000080000000\\ 0e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000\\ 504500004c0103009c809b500000000000000000e00002210b0108000008000000060000000000001e2700000020000000400000000040000020000000020000\\ 04000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000\\ cc2600004f000000004000004803000000000000000000000000000000000000006000000c000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002e74657874000000\\ 24070000002000000008000000020000000000000000000000000000200000602e72737263000000480300000040000000040000000a00000000000000000000\\ 00000000400000402e72656c6f6300000c0000000060000000020000000e00000000000000000000000000004000004200000000000000000000000000000000\\ 00270000000000004800000002000500642100006805000001000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 0000000000000000000000000000000013300400510000000100001100026f0400000a16fe01130411042d04020d2b3b026f0500000a0a730600000a0b071717\\ 730700000a0c080616068e696f0800000a00086f0900000a00086f0a00000a00140c07730b00000a0d2b00092a0000001b300400820000000200001100026f04\\ 00000a16fe01130611062d050213052b6a026f0c00000a1617730700000a0a170b20102700000c088d0a0000010d730600000a1304002b0d0011040916076f08\\ 00000a0000060916086f0d00000a250b16fe02130611062ddf00de042600fe1a00de0c00066f0a00000a00140a00dc001104730b00000a13052b0011052a0000\\ 011c000000003900276000040b000001020039002e67000c000000001e02280e00000a2a42534a4201000100000000000c00000076322e302e35303732370000\\ 000005006c0000009c010000237e0000080200001802000023537472696e67730000000020040000080000002355530028040000100000002347554944000000\\ 380400003001000023426c6f620000000000000002000001471502000900000000fa013300160000010000000b0000000200000003000000020000000e000000\\ 0300000002000000010000000300000000000a00010000000000060056004f000a007e0069000600c900a9000600e900a9000a005401390106008e0184010e00\\ b1019b010600bf0184010e00c6019b01060002024f0006000c024f00000000000100000000000100010001001000400000000500010001005020000000009600\\ 87000a000100b02000000000960094000a0002005c21000000008618a3001100030000000100690100000100e8011900a30015002100a30011002900a3001100\\ 11006e01be0011007901c2003100a30011003900a300c7004100d601d0004100dc0111004100e20111001100a300d8001100f701ea0041000702ef000900a300\\ 110020001b001a002e000b0005012e0013000e01de00f70004800000000000000000000000000000000007010000020000000000000000000000010046000000\\ 000002000000000000000000000001005d000000000002000000000000000000000001004f00000000000000003c4d6f64756c653e0073705f5f617373656d62\\ 6c795f45384346423742355f363842445f343130455f413944465f4631334539314332344546452e646c6c007574696c73006d73636f726c6962005379737465\\ 6d004f626a6563740053797374656d2e446174610053797374656d2e446174612e53716c54797065730053716c427974657300666e5f5f636f6d707265737300\\ 666e5f5f6465636f6d7072657373002e63746f720053797374656d2e52756e74696d652e436f6d70696c6572536572766963657300436f6d70696c6174696f6e\\ 52656c61786174696f6e734174747269627574650052756e74696d65436f6d7061746962696c6974794174747269627574650073705f5f617373656d626c795f\\ 45384346423742355f363842445f343130455f413944465f463133453931433234454645004d6963726f736f66742e53716c5365727665722e53657276657200\\ 53716c46756e6374696f6e41747472696275746500626c6f62006765745f49734e756c6c006765745f4275666665720053797374656d2e494f004d656d6f7279\\ 53747265616d0053797374656d2e494f2e436f6d7072657373696f6e004465666c61746553747265616d0053747265616d00436f6d7072657373696f6e4d6f64\\ 6500577269746500466c75736800436c6f736500636f6d70726573736564426c6f62006765745f53747265616d0042797465005265616400457863657074696f\\ 6e00000000032000000000001ee0c5882932964486d9ccf1d71714510008b77a5c561934e0890600011209120903200001042001010880a20100020054020f49\\ 7344657465726d696e6973746963015455794d6963726f736f66742e53716c5365727665722e5365727665722e446174614163636573734b696e642c20537973\\ 74656d2e446174612c2056657273696f6e3d322e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d6237376135\\ 63353631393334653038390a4461746141636365737300000000032000020420001d05082003011221112502072003011d0508080520010112210b07051d0512\\ 19121d1209020420001221072003081d0508080d0707121d08081d0512191209020801000800000000001e01000100540216577261704e6f6e45786365707469\\ 6f6e5468726f777301000000f426000000000000000000000e270000002000000000000000000000000000000000000000000000002700000000000000000000\\ 00005f436f72446c6c4d61696e006d73636f7265652e646c6c0000000000ff250020400000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100\\ 000000004800000058400000ec0200000000000000000000ec0234000000560053005f00560045005200530049004f004e005f0049004e0046004f0000000000\\ bd04effe00000100000000000000000000000000000000003f000000000000000400000002000000000000000000000000000000440000000100560061007200\\ 460069006c00650049006e0066006f00000000002400040000005400720061006e0073006c006100740069006f006e00000000000000b0044c02000001005300\\ 7400720069006e006700460069006c00650049006e0066006f0000002802000001003000300030003000300034006200300000002c0002000100460069006c00\\ 65004400650073006300720069007000740069006f006e000000000020000000300008000100460069006c006500560065007200730069006f006e0000000000\\ 30002e0030002e0030002e00300000008c003600010049006e007400650072006e0061006c004e0061006d0065000000730070005f005f006100730073006500\\ 6d0062006c0079005f00450038004300460042003700420035005f0036003800420044005f0034003100300045005f0041003900440046005f00460031003300\\ 4500390031004300320034004500460045002e0064006c006c0000002800020001004c006500670061006c0043006f0070007900720069006700680074000000\\ 200000009400360001004f0072006900670069006e0061006c00460069006c0065006e0061006d0065000000730070005f005f0061007300730065006d006200\\ 6c0079005f00450038004300460042003700420035005f0036003800420044005f0034003100300045005f0041003900440046005f0046003100330045003900\\ 31004300320034004500460045002e0064006c006c000000340008000100500072006f006400750063007400560065007200730069006f006e00000030002e00\\ 30002e0030002e003000000038000800010041007300730065006d0062006c0079002000560065007200730069006f006e00000030002e0030002e0030002e00\\ 30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 002000000c0000002037000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\\ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 if (select value_in_use from sys.configurations where name like ''clr enabled'')=0 or (select value from sys.dm_clr_properties where name=''state'') =''CLR initialization permanently failed'' print ''-- CLR disabled or CLR init failed'' else begin if not exists(select * from sys.assemblies where name=''utility_core'') begin try print ''-- creating assembly utility core'' -- drop assembly utility_core create assembly utility_core from @asm with permission_set = safe exec('' create function [fn__compress] (@blob varbinary(max)) returns varbinary(max) as external name utility_core.utils.fn__compress;'') exec('' create function [fn__decompress] (@compressedblob varbinary(max)) returns varbinary(max) as external name utility_core.utils.fn__decompress;'') end try begin catch -- select @err_msg=error_message() print ''-- assembly utility core failed with msg:'' print isnull(error_message(),''???'') end catch -- assembly utility_core end -- clr tests -- ########################## -- ## -- ## end -- ## -- ######################################################## /* if @end=1 begin end */ goto ret -- =================================================================== errors == /* err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create or upgrade base system objects Parameters @opt options run run the inside code log_ddl init only this table (called by sp__script_trace_db) '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__utility_setup' exec sp__utility_setup @opt='run|begin' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__utility_setup: -- ====================================================================== fn__at select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__at',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__at') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__at') with nowait goto skip_fn__at end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__at') with nowait goto skip_fn__at end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__at') with nowait if exists( select top 1 null from sys.objects where name='fn__at' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__at] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091018\s.zaglio: added null control: nb: problem on '' '', see tests v:090211/S.Zaglio: optimized v:081110.0100/S.Zaglio: expanded @seps to nvarchar(32) v:080801/S.Zaglio: managed bug on tokens count and added @sep v:080730/S.Zaglio: managed bug on empty strings v:080714/S.Zaglio: return token position into tokens: b(a|b|c) -> 2 t:print dbo.fn__at(''a'',''a|b|c'',''|'') print dbo.fn__at(''d'',''a|b|c'',''|'') -->1 & 0 t:print dbo.fn__at(''a'',''b'',''|'') -->0 t:print dbo.fn__at(''a'','''',''|'') -->0 t:print dbo.fn__at(''a b c'',''b'','''') -->0 -- NB! infinite loop t:print dbo.fn__at('''',''a|b|c'',''|'') -->0 t:print isnull(dbo.fn__str_at(''a|b|c'',''|'',4),''(null)'') -->null t:print isnull(dbo.fn__str_at(''a'',''|'',3),''(null)'') --> null t:print isnull(dbo.fn__str_at(''a|'',''|'',3),''(null)'') -->null c:very slow. Must be optimized */ CREATE function fn__at( @token sysname, @tokens nvarchar(4000), @sep nvarchar(32)=''|'' ) returns int as begin declare @i int if not @tokens is null select @i=pos from dbo.fn__str_table(@tokens,@sep) where token=@token return coalesce(@i,0) /* -- old version declare @n int declare @st sysname set @i=1 set @n=dbo.fn__str_count(@tokens,@sep) while (@i<=@n) begin set @st=dbo.fn__str_at(@tokens,@sep,@i) if @st=@token return @i if @st is null break set @i=@i+1 end -- while return 0 */ end -- fn__at' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__at: -- ============================================================ fn__base64decode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__base64decode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120123 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__base64decode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__base64decode') with nowait goto skip_fn__base64decode end if @ver>120123 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__base64decode') with nowait goto skip_fn__base64decode end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__base64decode') with nowait if exists( select top 1 null from sys.objects where name='fn__base64decode' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__base64decode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120123\s.zaglio: convert a nvarchar with base 64 to text t:select dbo.fn__base64decode(''VABlAHMAdAAgAEQAYQB0AGEA'') -- Test Data */ CREATE function dbo.fn__base64decode ( @base64 nvarchar(max) ) returns nvarchar(max) as begin declare @bin nvarchar(max) select @bin= cast(cast(N'''' as xml).value( ''xs:base64Binary(sql:variable("@base64"))'', ''varbinary(max)'') as nvarchar(max)) return @bin end -- fn__base64decode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__base64decode: -- ============================================================ fn__base64encode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__base64encode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120123 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__base64encode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__base64encode') with nowait goto skip_fn__base64encode end if @ver>120123 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__base64encode') with nowait goto skip_fn__base64encode end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__base64encode') with nowait if exists( select top 1 null from sys.objects where name='fn__base64encode' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__base64encode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120123\s.zaglio: convert a nvarchar to base 64 code t:select dbo.fn__base64encode(''Test Data'') -- VABlAHMAdAAgAEQAYQB0AGEA */ CREATE function dbo.fn__base64encode ( @text nvarchar(max) ) returns nvarchar(max) as begin declare @bin varchar(max) select @bin= cast(N'''' as xml).value( ''xs:base64Binary(xs:hexBinary(sql:column("bin")))'', ''VARCHAR(MAX)'' ) from (select cast(@text as varbinary(max)) as bin) as tmp; return @bin end -- fn__base64encode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__base64encode: -- ======================================================= fn__binaryfloat2float select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__binaryfloat2float',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120904 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__binaryfloat2float') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__binaryfloat2float') with nowait goto skip_fn__binaryfloat2float end if @ver>120904 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__binaryfloat2float') with nowait goto skip_fn__binaryfloat2float end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__binaryfloat2float') with nowait if exists( select top 1 null from sys.objects where name='fn__binaryfloat2float' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__binaryfloat2float] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:binary,real,convert,c v:120904\s.zaglio: from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=81849 */ create function [dbo].[fn__binaryfloat2float] ( @binaryfloat binary(8) ) returns float as begin return sign(cast(@binaryfloat as bigint)) * (1.0 + (cast(@binaryfloat as bigint) & 0x000fffffffffffff) * power(cast(2 as float), -52)) * power(cast(2 as float), (cast(@binaryfloat as bigint) & 0x7ff0000000000000) / 0x0010000000000000 - 1023) end -- [fn__binaryfloat2float]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__binaryfloat2float: -- ========================================================= fn__binaryreal2real select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__binaryreal2real',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120904 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__binaryreal2real') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__binaryreal2real') with nowait goto skip_fn__binaryreal2real end if @ver>120904 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__binaryreal2real') with nowait goto skip_fn__binaryreal2real end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__binaryreal2real') with nowait if exists( select top 1 null from sys.objects where name='fn__binaryreal2real' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__binaryreal2real] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:binary,real,convert,c v:120904\s.zaglio: from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=81849 */ create function [dbo].[fn__binaryreal2real] ( @binaryfloat binary(4) ) returns real as begin return sign(cast(@binaryfloat as int)) * (1.0 + (cast(@binaryfloat as int) & 0x007fffff) * power(cast(2 as real), -23)) * power(cast(2 as real), (cast(@binaryfloat as int) & 0x7f800000) / 0x00800000 - 127) end -- fn__binaryreal2real' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__binaryreal2real: -- ================================================================== fn__breset select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__breset',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090428 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__breset') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__breset') with nowait goto skip_fn__breset end if @ver>090428 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__breset') with nowait goto skip_fn__breset end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__breset') with nowait if exists( select top 1 null from sys.objects where name='fn__breset' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__breset] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090428\S.Zaglio: provided only for study t:print dbo.fn__breset(6,2) -->4 */ CREATE function fn__breset(@src int, @val int) returns int as begin return @src & (~@val) end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__breset: -- ==================================================================== fn__bset select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__bset',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090428 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__bset') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__bset') with nowait goto skip_fn__bset end if @ver>090428 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__bset') with nowait goto skip_fn__bset end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__bset') with nowait if exists( select top 1 null from sys.objects where name='fn__bset' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__bset] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090428\S.Zaglio: provided only for study t:print dbo.fn__bset(4,2) -->6 */ CREATE function fn__bset(@src int, @val int) returns int as begin return @src | @val end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__bset: -- =============================================================== fn__charcount select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__charcount',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100204 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__charcount') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__charcount') with nowait goto skip_fn__charcount end if @ver>100204 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__charcount') with nowait goto skip_fn__charcount end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__charcount') with nowait if exists( select top 1 null from sys.objects where name='fn__charcount' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__charcount] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100204\s.zaglio: count char occurrence todo:deprecate to fn__occurrences t:print dbo.fn__charcount(''.'',''schema.table.fld'') t:print dbo.fn__charcount(''.'',''schema_table_fld'') t:print dbo.fn__charcount(''.'',null) */ CREATE function [dbo].[fn__charcount](@char nchar(1),@string nvarchar(4000)) returns int as begin declare @i int,@nc int if @string is null or @char is null return null select @i=charindex(@char,@string),@nc=0 while (@i>0) begin select @nc=@nc+1 select @i=charindex(@char,@string,@i+1) end return @nc end -- end fn__charindex' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__charcount: -- =============================================================== fn__charindex select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__charindex',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130902 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__charindex') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__charindex') with nowait goto skip_fn__charindex end if @ver>130902 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__charindex') with nowait goto skip_fn__charindex end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__charindex') with nowait if exists( select top 1 null from sys.objects where name='fn__charindex' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__charindex] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130902,130830\s.zaglio: a bug when len(@what)>1;optimized from 2x to 4x v:111223\s.zaglio: upgraded to int indexes v:111111\s.zaglio: managed search of '' '' backwards v:091217\s.zaglio: a bug on right 1st char v:091015\s.zaglio: as charindex but can search from end to begin t:print dbo.fn__charindex(''\'',''c:\test\test2'',0) -- null t:print dbo.fn__charindex(''\'',''c:\test\test2'',-1) -- 8 t:print dbo.fn__charindex(''\'',''c:\test\test2'',-9) -- 3 t:print dbo.fn__charindex(''\'',null,-1) -- null t:print charindex(''\'',null) -- null t:print dbo.fn__charindex('']'',''end]'',-1) -- 4 t:print dbo.fn__charindex('' '',''left rght'',-1) -- 5 t:print dbo.fn__charindex(''\'',''nothing do find'',-1) -- 0 t:print dbo.fn__charindex('' from '',''select * from #objs '',-1) -- 9 */ CREATE function fn__charindex( @what nvarchar(4000), @where nvarchar(4000), @from int ) returns int as begin declare @i int,@n int,@m int if @from>=0 return null -- prevent use of this instead of charindex select @from=-@from,@n=len(''.''+@where+''.'')-2,@m=len(''.''+@what+''.'')-2 select @i=charindex(reverse(@what),reverse(@where),@from) if @i>0 return @n-@i+1-@m+1 return 0 end -- end fn__charindex' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__charindex: -- =============================================================== fn__chk_email select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__chk_email',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121004.1424 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__chk_email') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__chk_email') with nowait goto skip_fn__chk_email end if @ver>121004.1424 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__chk_email') with nowait goto skip_fn__chk_email end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__chk_email') with nowait if exists( select top 1 null from sys.objects where name='fn__chk_email' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__chk_email] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:121004.1424\s.zaglio: accept empty email when uses @seps v:121004\s.zaglio: changed fn__chk_str to fn__str_chk and used multi @seps v:110720\s.zaglio: added null/empty test v:110408\s.zaglio: return wrong emails instead of a boolean v:110219\s.zaglio: check if @email is correct and return wrongs t:print dbo.fn__chk_email(''me.you@me@you'',default) -- ko t:print dbo.fn__chk_email(''me.you@m-e'',default) -- null t:print dbo.fn__chk_email(''me@#me'',default) -- ko t:print dbo.fn__chk_email(''me@me;you@you'','';'') -- null t:print dbo.fn__chk_email(''me@me;you@U#U'','';'') -- ko t:print dbo.fn__chk_email(''me.youm-e'',default) -- ko t:print dbo.fn__chk_email(''me@you.com'',default) -- ok t:print dbo.fn__chk_email(''ok@ok.ok;me.youm-e;ok@ok.ok'','';'') -- ko t:print dbo.fn__chk_email(''ok1@ok.ok;ok2@ok.ok;'','';,'') -- ok t:print dbo.fn__chk_email(''ok1@ok.ok;;'','';,'') -- ok t:sp__find ''fn__chk_email'' */ CREATE function fn__chk_email(@email nvarchar(4000),@seps nvarchar(32)) returns nvarchar(4000) as begin declare @chars nvarchar(32),@token nvarchar(1024),@wrong nvarchar(1024), @i int select @chars=''-a-z0-9_.@'' -- !#$%&''*+-/=?^_`{|}~ -- empty or null email is an error (forgotten?) if isnull(@email,'''')='''' return '''' if @seps is null begin if dbo.fn__str_count(@email,''@'')!=2 or dbo.fn__str_chk(@email,@chars)=0 -- not exists return @email end -- single mail select @i=1 while 1=1 begin select @token=dbo.fn__str_parse(@email,@seps,@i) -- select dbo.fn__str_parse(''ok1@ok.ok;ok2@ok.ok;'','';,'',1) if @token is null break if @token!='''' and (dbo.fn__str_count(@token,''@'')!=2 or dbo.fn__str_chk(@token,@chars)!=1 ) select @wrong=isnull(@wrong+left(@seps,1),'''')+@token select @i=@i+1 end -- while of cursor return @wrong end -- fn__chk_email' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__chk_email: -- ================================================================= fn__comment select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__comment',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100328 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__comment') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__comment') with nowait goto skip_fn__comment end if @ver>100328 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__comment') with nowait goto skip_fn__comment end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__comment') with nowait if exists( select top 1 null from sys.objects where name='fn__comment' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__comment] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100328\s.zaglio: adapted to fn__comment_types v:100204\s.zaglio: return comment of obj */ CREATE function [dbo].[fn__comment](@path sysname) returns nvarchar(4000) as begin declare @schema sysname,@prop sysname, @obj sysname,@obj_type sysname, @col sysname,@col_type sysname, @comment nvarchar(4000),@id int, @xtype nvarchar(2),@sch_type sysname select @prop=prop,@schema=sch,@sch_type=sch_type, @obj_type=obj_type,@obj=obj, @col_type=sub_type,@col=sub from dbo.fn__comment_types(@path) select @comment=convert(nvarchar(4000),value) from fn_listextendedproperty ( @prop, @sch_type, @schema, @obj_type, @obj, @col_type, @col); return @comment end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__comment: -- ================================================================== fn__config select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__config',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__config') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__config') with nowait goto skip_fn__config end if @ver>131117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__config') with nowait goto skip_fn__config end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__config') with nowait if exists( select top 1 null from sys.objects where name='fn__config' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__config] begin try exec dbo.sp_executesql @statement = N' /* leave this l:see LICENSE file g:utility d:131117\s.zaglio: sp__config v:131117\s.zaglio: adapted to new cfg v:101019\s.zaglio: added autogeneration from sp__config. v:100424\s.zaglio: added inline-inmemory variables manag. v:100405\s.zaglio: uses of table if exists v:081218\S.Zaglio: usefull for personalization t:select dbo.fn__config(''smtp_server'',null) t:insert cfg select 0,0,''smtp_server'',''10.0.0.148'' */ CREATE function [dbo].[fn__config](@var sysname,@default sql_variant=null) returns sql_variant as begin declare @v sql_variant if left(@var,4)=''mem.'' begin select @var=substring(@var,5,128) select @v= case @var when ''mem.test1'' then ''mem.test1'' -- memory var test when ''mem.test'' then ''mem.test'' -- memory var test else null end -- case return @v end if object_id(''cfg'') is null return @default if left(@var,1) like ''[0-9]'' select @v=val from cfg where id=@var else select @v=val from cfg where [key]=@var return isnull(@v,@default) end -- fn__config' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__config: -- ============================================================== fn__config_app select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__config_app',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131125 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__config_app') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__config_app') with nowait goto skip_fn__config_app end if @ver>131125 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__config_app') with nowait goto skip_fn__config_app end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__config_app') with nowait if exists( select top 1 null from sys.objects where name='fn__config_app' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__config_app] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:config,utility,application,fn_config,fn__config v:131125\s.zaglio: when not find into _config, do NOT search in __config v:131122\s.zaglio: mixed and moved code from sp__job_status r:131117\s.zaglio: multiple config search t:select dbo.fn__config_app(''.test'',''nop'') -- from _ or nop t:select dbo.fn__config_app(''.test|test'',''nop'') -- from _ t:select dbo.fn__config_app(''.test1|noexists1|test1'',''nop'') -- from __ t:select dbo.fn__config_app(''.test1|noexists1|noexists2'',''nop'') -- nop t:select dbo.fn__config(''test'',''nop''),dbo.fn__config(''test1'',''nop'') t:drop function fn_config t:select dbo.fn__config_app(''.test|test'',''nop'') -- from __ */ CREATE function fn__config_app(@vars nvarchar(256), @default sql_variant) returns sql_variant as begin /* drop function fn_config create function fn_config(@param sysname,@defval sysname) returns sysname as begin declare @s sysname select @s=isnull(case @param when ''TEST'' then ''from _'' else null end,@defval) return @s end */ declare @v sql_variant,@var sysname,@fn_id int select @fn_id=isnull(object_id(''fn_config''),0) -- do a minimal check to ensure a sign compatibility with -- generic application FN_CONFIG declare cs cursor local for select token from fn__str_split(@vars,''|'') open cs while 1=1 begin fetch next from cs into @var if @@fetch_status!=0 break if left(@var,1)=''.'' begin select @var=substring(@var,2,256) if @fn_id!=0 select @v=dbo.fn_config(@var,cast(@default as nvarchar(4000))) end else select @v=dbo.fn__config(@var,@default) if @v=@default select @v=null if not @v is null break end -- cursor cs close cs deallocate cs select @v=isnull(@v,@default) return @v end -- fn__config_app' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__config_app: -- ============================================================ fn__context_info select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__context_info',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120724 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__context_info') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__context_info') with nowait goto skip_fn__context_info end if @ver>120724 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__context_info') with nowait goto skip_fn__context_info end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__context_info') with nowait if exists( select top 1 null from sys.objects where name='fn__context_info' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__context_info] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120724\s.zaglio: return position of @val into context else 0 */ CREATE function fn__context_info(@val sysname) returns int as begin declare @i int,@info varbinary(128),@code binary(2) select @code=dbo.fn__crc16(@val) select @info=context_info(),@i=1 while (@i120116 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__count') with nowait goto skip_fn__count end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__count') with nowait if exists( select top 1 null from sys.objects where name='fn__count' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__count] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120116\s.zaglio: fast row cnt. function version of sp__count t:select dbo.fn__count(''cfg'') */ CREATE function fn__count(@tbl sysname) returns bigint as begin declare @n bigint --SQL Server 2000+ (work well also in 2k5) SELECT @n= si.rowcnt FROM sysindexes si JOIN sysobjects so ON si.id = so.id WHERE si.indid < 2 --clustered index or heap AND OBJECTPROPERTY(so.id, ''IsMSShipped'') = 0 AND so.xtype=''u'' and so.name=@tbl /* SQL Server 2005+ give also schema -- originally from -- http://developerspla.net/2010/sql-server/tsql/row-count-of-all-tables/ SELECT [TableName] = OBJECT_SCHEMA_NAME(sp.[object_id]) + ''.'' + OBJECT_NAME(sp.[object_id]) ,[RowCount] = SUM(sp.rows) FROM sys.partitions sp WHERE OBJECT_SCHEMA_NAME(sp.[object_id]) <> ''sys'' AND sp.index_id < 2 GROUP BY object_id ORDER BY [RowCount] DESC */ return @n end -- fn__count' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__count: -- =================================================================== fn__crc16 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__crc16',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130901 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__crc16') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__crc16') with nowait goto skip_fn__crc16 end if @ver>130901 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__crc16') with nowait goto skip_fn__crc16 end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__crc16') with nowait if exists( select top 1 null from sys.objects where name='fn__crc16' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__crc16] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility d:130202\s.zaglio: fn__crc16_tbl v:130901\s.zaglio: correction for unicode>32768 v:130202\s.zaglio: embedded lookup table, 5 times faster v:090614\S.Zaglio: used by fn_crc16 t: print dbo.fn__crc16('''') -- 0 print dbo.fn__crc16(''a'') -- 22398 print dbo.fn__crc16(''b'') -- 22078 print dbo.fn__crc16(''aa'') -- -30633 print dbo.fn__crc16(''ab'') -- -30441 print dbo.fn__crc16(''ba'') -- 30805 print dbo.fn__crc16(N''ウィ'') -- -30571 */ CREATE function [dbo].[fn__crc16]( @string nvarchar(4000) ) returns smallint as begin declare @lookup binary(512) select @lookup = 0x\\ 0000C0C1C1810140C30103C00280C241C60106C00780C7410500C5C1C4810440CC010CC00D80\\ CD410F00CFC1CE810E400A00CAC1CB810B40C90109C00880C841D80118C01980D9411B00DBC1\\ DA811A401E00DEC1DF811F40DD011DC01C80DC411400D4C1D5811540D70117C01680D641D201\\ 12C01380D3411100D1C1D0811040F00130C03180F1413300F3C1F28132403600F6C1F7813740\\ F50135C03480F4413C00FCC1FD813D40FF013FC03E80FE41FA013AC03B80FB413900F9C1F881\\ 38402800E8C1E9812940EB012BC02A80EA41EE012EC02F80EF412D00EDC1EC812C40E40124C0\\ 2580E5412700E7C1E68126402200E2C1E3812340E10121C02080E041A00160C06180A1416300\\ A3C1A28162406600A6C1A7816740A50165C06480A4416C00ACC1AD816D40AF016FC06E80AE41\\ AA016AC06B80AB416900A9C1A88168407800B8C1B9817940BB017BC07A80BA41BE017EC07F80\\ BF417D00BDC1BC817C40B40174C07580B5417700B7C1B68176407200B2C1B3817340B10171C0\\ 7080B041500090C191815140930153C052809241960156C057809741550095C1948154409C01\\ 5CC05D809D415F009FC19E815E405A009AC19B815B40990159C058809841880148C049808941\\ 4B008BC18A814A404E008EC18F814F408D014DC04C808C41440084C185814540870147C04680\\ 8641820142C043808341410081C180814040 declare @crc smallint declare @c tinyint declare @t tinyint declare @a smallint declare @i smallint declare @u int set @a=0 set @crc = 0xFFFF set @i=1 declare @l int set @l=len(@string) while (@i<=@l) begin set @u=unicode(substring(@string,@i,1)) set @c=@u % 256 set @t=(@crc^@c)&0xff set @a=@crc/256 set @crc=@a ^ substring(@lookup,@t*2+1,2) set @c=@u / 256 if @c!=0 begin -- this keep compatibility with old nvarchar crc32 -- and also the whole performances set @t=(@crc^@c)&0xff set @a=@crc/256 set @crc=@a ^ substring(@lookup,@t*2+1,2) end set @i=@i+1 end set @crc= ~@crc return @crc end -- fn__crc16' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__crc16: -- =================================================================== fn__crc32 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__crc32',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130901 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__crc32') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__crc32') with nowait goto skip_fn__crc32 end if @ver>130901 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__crc32') with nowait goto skip_fn__crc32 end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__crc32') with nowait if exists( select top 1 null from sys.objects where name='fn__crc32' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__crc32] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130901\s.zaglio: correct a bug near unicode>32768 v:130202\s.zaglio: embedded lookup table, 5 times faster d:130202\s.zaglio: fn__crc32_tbl v:110315\s.zaglio: @string to ntext v:090930\s.zaglio: a bug on the name of tbl v:090614\s.zaglio: calculate crc32 of a unicode & non unicode string t: select st,res,dbo.fn__crc32(st) crc, case when dbo.fn__crc32(st)=res then ''ok'' else ''ko'' end st from ( select ''jhon'' st,2071226836 res union select N''Джон'',877079858 union select ''j'',2137352139 union select N''Д'',1746534835 union select N''�'',-842440062 ) data t: -- mega test declare @v nvarchar(max),@i int select @i=10000,@v=''start\n'' while (@i>0) select @v=@v+''01234567890\n'',@i=@i-1 select @v=@v+''end'' print datalength(@v) -- 260020 declare @d datetime select @d=getdate() print dbo.fn__crc32(@v) -- 531861221 exec sp__elapsed @d,'''' -- 440ms */ CREATE function [dbo].[fn__crc32]( @string nvarchar(max) ) returns int as begin declare @crc int declare @u int -- to containt an unsigned smallint declare @c tinyint declare @t tinyint declare @a int declare @i int declare @lookup varbinary(2048) select @lookup = 0x\\ 0000000077073096ee0e612c990951ba076dc419706af48fe963a5359e6495a30edb8832\\ 79dcb8a4e0d5e91e97d2d98809b64c2b7eb17cbde7b82d0790bf1d911db710646ab020f2\\ f3b9714884be41de1adad47d6ddde4ebf4d4b55183d385c7136c9856646ba8c0fd62f97a\\ 8a65c9ec14015c4f63066cd9fa0f3d638d080df53b6e20c84c69105ed56041e4a2677172\\ 3c03e4d14b04d447d20d85fda50ab56b35b5a8fa42b2986cdbbbc9d6acbcf94032d86ce3\\ 45df5c75dcd60dcfabd13d5926d930ac51de003ac8d75180bfd0611621b4f4b556b3c423\\ cfba9599b8bda50f2802b89e5f058808c60cd9b2b10be9242f6f7c8758684c11c1611dab\\ b6662d3d76dc419001db710698d220bcefd5102a71b1858906b6b51f9fbfe4a5e8b8d433\\ 7807c9a20f00f9349609a88ee10e98187f6a0dbb086d3d2d91646c97e6635c016b6b51f4\\ 1c6c6162856530d8f262004e6c0695ed1b01a57b8208f4c1f50fc45765b0d9c612b7e950\\ 8bbeb8eafcb9887c62dd1ddf15da2d498cd37cf3fbd44c654db261583ab551cea3bc0074\\ d4bb30e24adfa5413dd895d7a4d1c46dd3d6f4fb4369e96a346ed9fcad678846da60b8d0\\ 44042d7333031de5aa0a4c5fdd0d7cc95005713c270241aabe0b1010c90c20865768b525\\ 206f85b3b966d409ce61e49f5edef90e29d9c998b0d09822c7d7a8b459b33d172eb40d81\\ b7bd5c3bc0ba6cadedb883209abfb3b603b6e20c74b1d29aead547399dd277af04db2615\\ 73dc1683e3630b1294643b840d6d6a3e7a6a5aa8e40ecf0b9309ff9d0a00ae277d079eb1\\ f00f93448708a3d21e01f2686906c2fef762575d806567cb196c36716e6b06e7fed41b76\\ 89d32be010da7a5a67dd4accf9b9df6f8ebeeff917b7be4360b08ed5d6d6a3e8a1d1937e\\ 38d8c2c44fdff252d1bb67f1a6bc57673fb506dd48b2364bd80d2bdaaf0a1b4c36034af6\\ 41047a60df60efc3a867df55316e8eef4669be79cb61b38cbc66831a256fd2a05268e236\\ cc0c7795bb0b4703220216b95505262fc5ba3bbeb2bd0b282bb45a925cb36a04c2d7ffa7\\ b5d0cf312cd99e8b5bdeae1d9b64c2b0ec63f226756aa39c026d930a9c0906a9eb0e363f\\ 720767850500571395bf4a82e2b87a147bb12bae0cb61b3892d28e9be5d5be0d7cdcefb7\\ 0bdbdf2186d3d2d4f1d4e24268ddb3f81fda836e81be16cdf6b9265b6fb077e118b74777\\ 88085ae6ff0f6a7066063bca11010b5c8f659efff862ae69616bffd3166ccf45a00ae278\\ d70dd2ee4e0483543903b3c2a7672661d06016f74969474d3e6e77dbaed16a4ad9d65adc\\ 40df0b6637d83bf0a9bcae53debb9ec547b2cf7f30b5ffe9bdbdf21ccabac28a53b39330\\ 24b4a3a6bad03605cdd7069354de572923d967bfb3667a2ec4614ab85d681b022a6f2b94\\ b40bbe37c30c8ea15a05df1b2d02ef8d select @a=0 select @crc = 0xFFFFFFFF select @i=1 declare @l int select @l=datalength(@string)/2 while (@i<=@l) begin -- select unicode(N''�'')/256 select @u=unicode(substring(@string,@i,1)) select @c=@u % 256 select @t=(@crc & 0xff) ^ @c select @a=(@crc & 0x7FFFFFFF)/256 if (@crc & 0x80000000)<>0 select @a=@a | 0x800000 select @crc=@a ^ substring(@lookup,@t*4+1,4) select @c=@u / 256 if @c!=0 begin -- this keep compatibility with old nvarchar crc32 and also the whole performances select @t=(@crc & 0xff) ^ @c select @a=(@crc & 0x7FFFFFFF)/256 if (@crc & 0x80000000)<>0 select @a=@a | 0x800000 select @crc=@a ^ substring(@lookup,@t*4+1,4) end -- zero char select @i=@i+1 end select @crc= @crc ^ 0xFFFFFFFF return @crc end -- [fn__crc32]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__crc32: -- ==================================================================== fn__date select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__date',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__date') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__date') with nowait goto skip_fn__date end if @ver>131117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__date') with nowait goto skip_fn__date end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__date') with nowait if exists( select top 1 null from sys.objects where name='fn__date' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__date] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:date,without,time,getdate,convert,number s:fn__time v:131117\s.zaglio: out a int instead of a date to align to fn__time v:130828\s.zaglio: return a date without time (more a reminder that to use everyday) t:select dbo.fn__date(getdate()) t: select -- round a date to the nearest quarter cast(floor(cast(getdate() as float(53))*24*4)/(24*4) as datetime), -- faster but untill y5500; there was rounding issues at 30 and 00 dateadd(minute, datediff(minute,0,getdate()) / 15 * 15, 0), -- last 15 minute increment, not the nearest cast(round(floor(cast(getdate() as float(53))*24*4)/(24*4),5) as smalldatetime) */ CREATE function fn__date(@dt datetime) returns int as begin return cast(convert(varchar(8),dateadd(dd, datediff(dd, 0, getdate())+0, 0),112) as int) end -- fn__date' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__date: -- ================================================================= fn__dateadd select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__dateadd',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=101008 begin if @aut!='g.sorgente' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__dateadd') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__dateadd') with nowait goto skip_fn__dateadd end if @ver>101008 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__dateadd') with nowait goto skip_fn__dateadd end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__dateadd') with nowait if exists( select top 1 null from sys.objects where name='fn__dateadd' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__dateadd] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:101008\g.sorgente: add value to a date, avoiding overflow t: declare @d datetime set @d=getdate() print dbo.fn__dateadd(@d,5) print dbo.fn__dateadd(@d,-5) set @d=''9999-12-30T23:59:59.998'' print dbo.fn__dateadd(@d,5) */ create function dbo.fn__dateadd ( @dt datetime=null ,@days int=null ) returns datetime as begin declare @dtmax datetime set @dtmax=convert(datetime,''9999-12-31T23:59:59.998'') if (@days<0) set @dt=dateadd(day,@days,@dt) else begin -- evito l''overflow verificando di non superare il 9999-12-31 if @dt<=dateadd(day,-@days,@dtmax) set @dt=dateadd(day,@days,@dt) else set @dt=@dtmax end return @dt end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__dateadd: -- ======================================================== fn__dt_first_weekday select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__dt_first_weekday',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__dt_first_weekday') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__dt_first_weekday') with nowait goto skip_fn__dt_first_weekday end if @ver>131117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__dt_first_weekday') with nowait goto skip_fn__dt_first_weekday end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__dt_first_weekday') with nowait if exists( select top 1 null from sys.objects where name='fn__dt_first_weekday' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__dt_first_weekday] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:date,first,day,week,set DATEFIRST c:http://stackoverflow.com/questions/7168874/get-first-day-of-week-in-sql-server c:more a reminder that to use everyday v:131117\s.zaglio: get 1st day of week t:select dbo.fn__dt_first_weekday(getdate()) */ CREATE function fn__dt_first_weekday( -- always the datefirst weekday @d smalldatetime ) returns smalldatetime as begin return (select dateadd(day, 1-datepart(weekday, @d), @d)); end -- fn__dt_first_weekday' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__dt_first_weekday: -- ======================================================= fn__dt_sunday_of_week select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__dt_sunday_of_week',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__dt_sunday_of_week') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__dt_sunday_of_week') with nowait goto skip_fn__dt_sunday_of_week end if @ver>131117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__dt_sunday_of_week') with nowait goto skip_fn__dt_sunday_of_week end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__dt_sunday_of_week') with nowait if exists( select top 1 null from sys.objects where name='fn__dt_sunday_of_week' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__dt_sunday_of_week] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:date,first,day,sunday,set datefirst c:http://stackoverflow.com/questions/7168874/get-first-day-of-week-in-sql-server c:more a reminder that to use everyday v:131117\s.zaglio: get 1st sunday of week t:select dbo.fn__dt_sunday_of_week(getdate()) */ create function dbo.fn__dt_sunday_of_week ( @d smalldatetime ) returns smalldatetime as begin return (select dateadd(week, datediff(week, ''19050101'', @d), ''19050101'')); end -- fn__dt_sunday_of_week' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__dt_sunday_of_week: -- ================================================================== fn__exists select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__exists',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__exists') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__exists') with nowait goto skip_fn__exists end if @ver>100919.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__exists') with nowait goto skip_fn__exists end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__exists') with nowait if exists( select top 1 null from sys.objects where name='fn__exists' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__exists] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919.1000\s.zaglio: added type "fl" for field v:100612\s.zaglio: better code; NB: for files/dir, use sp__dir v:091001\S.Zaglio: added management of #t v:090915\S.Zaglio: forwarded fkey test from rkey to fkey on sysfkeys v:090815\S.Zaglio: a remake using object_id() v:090813\S.Zaglio: manage of [quoted] names v:090705\S.Zaglio: added management of global temp tables v:090130\S.Zaglio: added db management in names (loosed type check) v:081217\S.Zaglio: added multiple check with and or or and (nolock) v:081207\S.Zaglio: added foreign keys check if @type=''fk'' v:081021\S.Zaglio: added owner v:080808\S.Zaglio: check existance of obj of type. If type is null, find any t:print object_id(''dbo.sysobjects'') t: print dbo.fn__exists(''[sysobjects]'',null) -->1 t: print dbo.fn__exists(''sysobjects'',null) -->1 t: print dbo.fn__exists(''dbo.sysobjects'',null) -->1 t: print dbo.fn__exists(''dbo.sysobjects'',''X'') -->1 t: print dbo.fn__exists(''sys.sysobjects'',null) -->1 t: print dbo.fn__exists(''nothing.sysobjects'',null) -->0 t: print dbo.fn__exists(''sysobjects,syscolumns'',null) -->1 and condition t: print dbo.fn__exists(''sysobjects|sysnothing'',null) -->1 or condition t: print dbo.fn__exists(''sysobjects,sysnothing'',null) -->0 and condition t: create table ##test(id int) print dbo.fn__exists(''##test'',null) exec sp__drop ''##test'' -- 1 t: create table #test(id int) print dbo.fn__exists(''#test'',null) exec sp__drop ''#test'' -- 1 t: create table test_fn_exists(a int) print dbo.fn__exists(''test_fn_exists'',default) print dbo.fn__exists(''test_fn_exists.a'',''fl'') print dbo.fn__exists(''test_fn_exists.notex'',''fl'') drop table test_fn_exists */ CREATE function [dbo].[fn__exists]( @objects nvarchar(4000), @type nvarchar(2) = null ) returns tinyint as begin -- note: object_id uses dbo as default when not specified -- select @objects=''[sysobjects]'',@type=null <---- BE CAREFULL -- declare @dbg bit,@objects nvarchar(4000), @type nvarchar(2) select @objects=''test_fn_exists.a'',@dbg=1 declare @stdout table(lno int identity,line nvarchar(4000)) declare @exists bit, @owner sysname, @obj sysname,@fld sysname, @cmd nvarchar(1024), @true tinyint,@false tinyint, @db sysname,@id int, @n int, @cond nchar(1) select @true=1,@false=0, @cond='','' if @objects is null goto ret if charindex('','',@objects)=0 set @cond=''|'' -- OR condition set @n=dbo.fn__str_count(@objects,@cond) while (@n>0 and (@exists is null or (not (@exists=0 and @cond='','') -- exists and exists... and not (@exists=1 and @cond=''|'') -- exists or exists ) ) ) begin -- dbo.fn__sql_unquotename not possibile because can be [dbo].[...] select @obj=dbo.fn__str_at(@objects,@cond,@n), @fld=null,@id=null, @n=@n-1 -- special case for field if @type=''fl'' select @fld=parsename(@obj,1),@obj=parsename(@obj,2) -- special case for temp if left(@obj,1)=''#'' or left(@obj,2)=''[#'' select @obj=''tempdb..''+@obj select @id=object_id(@obj) if @type=''fk'' -- foreign keys existance begin if exists( select null from dbo.sysforeignkeys fk with (nolock) where fkeyid=@id ) set @exists=@true else select @exists=@false end else begin if not @id is null begin select @exists=@true if not @fld is null and not exists( select top 1 null from syscolumns where id=@id and [name]=@fld ) select @exists=@false end -- obj.fld else select @exists=@false end -- normal obj end -- while ret: -- print @exists return @exists end -- fn__exists' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__exists: -- =================================================================== fn__flags select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flags',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120403 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flags') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flags') with nowait goto skip_fn__flags end if @ver>120403 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flags') with nowait goto skip_fn__flags end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flags') with nowait if exists( select top 1 null from sys.objects where name='fn__flags' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flags] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:obj,utility v:120403\s.zaglio: added to group utility v:120125\s.zaglio: return null when unk v:110323\s.zaglio: convert mnemonic flags to numeric t:select dbo.fn__flags(''ABCD''),dbo.fn__flags(''E'') t: select dbo.fn__flags(''P''),dbo.fn__hex(dbo.fn__flags(''P'')), dbo.fn__flags(''OP''),dbo.fn__hex(dbo.fn__flags(''OP'')), dbo.fn__flags(''AP''),dbo.fn__hex(dbo.fn__flags(''AP'')) t:select dbo.fn__flags(''q'') -- error t:declare @s smallint select @s=32768 select 0xffff-@s */ CREATE function fn__flags(@flags nvarchar(16)) returns smallint as begin declare @ret smallint,@i int,@l int if isnumeric(@flags)=1 return convert(smallint,@flags) select @ret=0,@i=1,@l=len(@flags) while (@i<=@l) begin select @ret= case substring(@flags,@i,1) when ''a'' then @ret|1 -- 1 when ''b'' then @ret|2 -- 2 when ''c'' then @ret|4 -- 3 when ''d'' then @ret|8 -- 4 when ''e'' then @ret|16 when ''f'' then @ret|32 when ''g'' then @ret|64 when ''h'' then @ret|128 -- 8 when ''i'' then @ret|256 when ''j'' then @ret|512 when ''k'' then @ret|1024 when ''l'' then @ret|2048 when ''m'' then @ret|4096 when ''n'' then @ret|8192 when ''o'' then @ret|16384 when ''p'' then ~@ret -- 16 else null end select @i=@i+1 end return @ret end -- fn__flags' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flags: -- ================================================================= fn__flags32 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flags32',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120404 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flags32') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flags32') with nowait goto skip_fn__flags32 end if @ver>120404 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flags32') with nowait goto skip_fn__flags32 end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flags32') with nowait if exists( select top 1 null from sys.objects where name='fn__flags32' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flags32] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:obj,utility v:120404\s.zaglio: convert a,b,c,... into power of 2 t:select dbo.fn__flags32(''A''),dbo.fn__flags32(''AB''),dbo.fn__flags32(''Z'') t:select cast(dbo.fn__flags32(''AZ'') as binary(4)),dbo.fn__flags32(''AZ'') */ CREATE function fn__flags32(@flags nvarchar(32)) returns int as begin declare @ret int,@i int,@l int,@asc int, @asc_a int,@asc_z int if isnumeric(@flags)=1 return convert(int,@flags) select @ret=0,@i=1, @l=len(@flags), @asc_a=ascii(''A''), @asc_z=ascii(''Z'')-@asc_a, @flags=upper(@flags) while (@i<=@l) begin select @asc=ascii(substring(@flags,@i,1))-@asc_a if @asc=@asc_z select @ret=~@ret else select @ret=@ret|power(2,@asc) select @i=@i+1 end return @ret end -- fn__flags32' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flags32: -- ============================================================ fn__flds_convert select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_convert',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131014 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_convert') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_convert') with nowait goto skip_fn__flds_convert end if @ver>131014 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_convert') with nowait goto skip_fn__flds_convert end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_convert') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_convert' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_convert] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131014\s.zaglio: d tag adjust v:100228\s.zaglio: standard types convertion for tables d:100228\s.zaglio: fn__flds_row t: create table test_convert(a int,b float,c datetime,t sysname) select * into #test_convert from test_convert select * into ##test_convert from test_convert print ''table:''+dbo.fn__flds_convert(''test_convert'',null,''t'') print ''#table:''+dbo.fn__flds_convert(''#test_convert'',null,null) print ''##table:''+dbo.fn__flds_convert(''##test_convert'',null,null) print isnull(dbo.fn__flds_convert(null,null,null),''???'') drop table test_convert drop table #test_convert drop table ##test_convert */ CREATE function [dbo].[fn__flds_convert]( @tbl sysname, @seps nvarchar(32)='','', @excludes sysname='''' ) returns nvarchar(4000) as begin declare @convs nvarchar(4000),@db sysname,@obj sysname,@i int declare @ex table([name] sysname) if @seps is null select @seps='','' -- print parsename(''[db..obj]'',1) -- print parsename(''db..[obj]'',1) select @db=parsename(@tbl,3) select @obj=parsename(@tbl,1) if left(@obj,1)=''#'' select @tbl=''tempdb..''+@obj if not @excludes is null insert @ex select token from dbo.fn__str_table(@excludes,@seps) if left(@obj,1)=''#'' select @convs=coalesce( @convs + @seps, '''') + case when t.name in (''datetime'', ''smalldatetime'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',126) as '' + quotename(c.name) when t.name in (''numeric'', ''decimal'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',128) as '' + quotename(c.name) when t.name in (''float'', ''real'', ''money'', ''smallmoney'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',2) as '' + quotename(c.name) when t.name in (''datetime'', ''smalldatetime'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',120) as '' + quotename(c.name) when t.name in (''image'',''text'',''ntext'') then ''dbo.fn__hex(textptr(''+quotename(c.name)+'')) as '' + quotename(c.name) else quotename(c.name) end from tempdb..syscolumns c join tempdb..systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@tbl) and not c.name in (select [name] from @ex) order by colorder else select @convs=coalesce( @convs + @seps, '''')+ case when t.name in (''datetime'', ''smalldatetime'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',126) as '' + quotename(c.name) when t.name in (''numeric'', ''decimal'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',128) as '' + quotename(c.name) when t.name in (''float'', ''real'', ''money'', ''smallmoney'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',2) as '' + quotename(c.name) when t.name in (''datetime'', ''smalldatetime'') then ''convert(nvarchar(4000),''+quotename(c.name)+'',120) as '' + quotename(c.name) when t.name in (''image'',''text'',''ntext'') then ''dbo.fn__hex(textptr(''+quotename(c.name)+'')) as '' + quotename(c.name) else quotename(c.name) end from syscolumns c join systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@obj) and not c.name in (select [name] from @ex) order by colorder return @convs end -- fn__flds_convert' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_convert: -- ================================================================= fn__flds_of select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_of',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130730 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_of') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_of') with nowait goto skip_fn__flds_of end if @ver>130730 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_of') with nowait goto skip_fn__flds_of end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_of') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_of' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_of] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130730\s.zaglio: adapted to mssql2k5 and replaced prev ordby with @tcol pkey v:130529\l.mazzanti: trovato un caso in cui si perdeva l''orderby del colorder v:121011\s.zaglio: added like on exclusions instead of = v:120413,100710\s.zaglio: add.%id% to exclude identity;order by number for table functions v:100228\s.zaglio: a remake more simple & faster (as fn__flds_convert) v:090915\S.Zaglio: added #temp table management v:081224,081121\S.Zaglio: manage quoted name;now @excludes need same @seps v:081110,081012\S.Zaglio: expanded @seps to nvarchar(32);expanded @seps to nvarchar(8) v:081009\S.Zaglio: added quoting for fields with spaces inside v:080721\S.Zaglio: return list of flields separated by comma with optional exlusions of flds separated by | t:sp__flds_of_test */ CREATE function [dbo].[fn__flds_of]( @tbl sysname, @seps nvarchar(32)='','', @excludes sysname='''' ) returns nvarchar(4000) as begin declare @cols nvarchar(4000),@db sysname,@obj sysname,@i int, @sql nvarchar(4000),@oid int,@tmp bit,@ex_ident bit, @nexcludes int declare @ex table([name] sysname primary key) declare @tcols table([name] sysname, colorder int primary key) if @seps is null select @seps='','' -- print parsename(''[db..obj]'',1) -- print parsename(''db..[obj]'',1) select @db=parsename(@tbl,3), @obj=parsename(@tbl,1), @tmp=case when left(@obj,1)=''#'' then 1 else 0 end, @ex_ident=charindex(''%id%'',@excludes) if (not @db is null and @db!=db_name()) return null if @tmp=1 select @tbl=''tempdb..''+@obj select @oid=object_id(@tbl) if @oid is null return null /* this fn is so slower that is better delete excludes to the end instead of while */ if not @excludes is null begin insert @ex select token from dbo.fn__str_table(@excludes,@seps) where token!=''%id%'' select @nexcludes=@@rowcount end -- collect cols if @ex_ident=1 begin if @tmp=1 insert @tcols select c.name, c.column_id -- select * from tempdb.sys.columns c where c.[object_id]=@oid and c.is_identity=0 order by column_id else insert @tcols select c.name, c.column_id from sys.columns c where c.[object_id]=@oid and is_identity=0 order by column_id end else -- with identity begin if @tmp=1 insert @tcols select c.name, c.column_id from tempdb.sys.columns c where c.[object_id]=@oid order by c.column_id else insert @tcols select c.name, c.column_id from sys.columns c where c.[object_id]=@oid order by column_id end if @nexcludes>0 delete a from @tcols a join @ex b on a.[name] like b.[name] select @cols=coalesce(@cols+@seps,'''')+c.name from @tcols c return @cols end -- fn__flds_of' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_of: -- ========================================================== fn__flds_quotename select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_quotename',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_quotename') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_quotename') with nowait goto skip_fn__flds_quotename end if @ver>100919 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_quotename') with nowait goto skip_fn__flds_quotename end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_quotename') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_quotename' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_quotename] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919\s.zaglio: quote numeric fields names v:100405\s.zaglio: re???added reserved keywords v:091128\s.zaglio: added use of fn__token_sql v:090916\S.Zaglio: added some keywords v:090627\S.Zaglio: added keywords as,where v:090304\S.Zaglio: add bounds [ & ] if have space or chars or is a keyword t:print dbo.fn__flds_quotename(''test,te/st,test test,test_test,group,set,[already_quoted]'','','') */ CREATE function [dbo].[fn__flds_quotename]( @flds nvarchar(4000), @seps nvarchar(32)='','' ) returns nvarchar(4000) as begin declare @r nvarchar(4000),@name sysname,@i int,@n int declare @t table (token sysname) insert @t select token from dbo.fn__str_table(@flds,@seps) update @t set token=quotename(token) where left(token,1)!=''['' and (patindex(''%[^0-9A-Za-z,_]%'', token)>0 or dbo.fn__token_sql(token)=1 or isnumeric(token)=1 ) select @r=coalesce(@r+@seps,'''')+token from @t /* set @r='''' set @i=1 set @n=dbo.fn__str_count(@flds,@seps) while (@i<=@n) begin set @name=dbo.fn__str_at(@flds,@seps,@i) if left(@name,1)<>''['' and right(@name,1)<>'']'' begin if charindex('' '',@name)>0 or dbo.fn__token_sql(@name)=1 set @name=quotename(@name) end if @i>1 set @r=@r+@seps set @r=@r+@name set @i=@i+1 end -- while */ return @r end -- fn__flds_quotename' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_quotename: -- =========================================================== fn__flds_row_size select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_row_size',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100501 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_row_size') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_row_size') with nowait goto skip_fn__flds_row_size end if @ver>100501 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_row_size') with nowait goto skip_fn__flds_row_size end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_row_size') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_row_size' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_row_size] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100501\s.zaglio: added @extra (for each columns) to calc nulls v:100228\s.zaglio: a correction on description (in bytes) v:091018\s.zaglio: return row size (in bytes) of fields of a table t: print dbo.fn__flds_row_size(''sysobjects'','','',''name,id,xtype'',default) select * from syscolumns where id=object_id(''sysobjects'') order by colid t: create table #test(a varchar(4),b nvarchar(4), c bit, d int) -- 4+8+?+4=16+? print dbo.fn__flds_row_size(''#test'','','',''a,b,c,d'',default) print dbo.fn__flds_row_size(''#test'','','',''a,b,c,d'',1) drop table #test t:sp__find ''fn__flds_row_size'' */ CREATE function [dbo].[fn__flds_row_size](@tbl sysname,@sep nvarchar(32),@flds nvarchar(4000),@extra real=0) returns int as begin declare @r int if @sep is null select @sep='','' select @flds=@sep+@flds+@sep if left(@tbl,1)=''#'' begin select @tbl=''tempdb..''+@tbl select @r=sum(length)+@extra*count(*) from tempdb..syscolumns where id=object_id(@tbl) and charindex(@sep+[name]+@sep,@flds)>0 end else select @r=sum(length)+@extra*count(*) from syscolumns where id=object_id(@tbl) and charindex(@sep+[name]+@sep,@flds)>0 return @r end -- func' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_row_size: -- ============================================================ fn__flds_size_of select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_size_of',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090916 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_size_of') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_size_of') with nowait goto skip_fn__flds_size_of end if @ver>090916 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_size_of') with nowait goto skip_fn__flds_size_of end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_size_of') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_size_of' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_size_of] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090916\S.Zaglio: a better managemnt of temp tables v:090202\S.Zaglio: return a series of field''s sizes of table t: print dbo.fn__flds_size_of(''sysobjects'',''|'',null) --> name and id and xtype ... */ CREATE function [dbo].[fn__flds_size_of](@tbl sysname, @seps nvarchar(32)='','',@excludes sysname='''') returns nvarchar(4000) as begin set @tbl=dbo.fn__sql_unquotename(@tbl) if @excludes<>'''' set @excludes=@excludes+@seps -- coz error into fn_str_at declare @flds nvarchar(4000) set @flds='''' declare @tmp bit if left(@tbl,1)=''#'' set @tbl=''tempdb..''+@tbl if charindex(''.#'',@tbl)>0 set @tmp=1 else set @tmp=0 if @tmp=0 declare flds cursor local for select convert(nvarchar(10),t.length) as length from syscolumns c inner join systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@tbl) order by colorder else declare flds cursor local for select convert(nvarchar(10),t.length) as length from tempdb..syscolumns c inner join tempdb..systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@tbl) order by colorder declare @fld sysname declare @i int declare @n int set @n=dbo.fn__str_count(@excludes,default) declare @no bit open flds while (1=1) begin fetch next from flds into @fld if @@error != 0 or @@fetch_status != 0 BREAK set @no=0 if @excludes<>'''' begin set @i=1 while (@i<=@n) begin if dbo.fn__at(@fld,@excludes,@seps)<>0 begin set @no=1 break end set @i=@i+1 end -- while end -- if @excludes if @no=0 begin if charindex('' '',@fld)>0 set @fld=quotename(@fld) if @flds<>'''' set @flds=@flds+@seps set @flds=@flds+@fld end -- @no end -- while cursor close flds deallocate flds return @flds end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_size_of: -- ============================================================ fn__flds_type_of select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__flds_type_of',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=151106 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__flds_type_of') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__flds_type_of') with nowait goto skip_fn__flds_type_of end if @ver>151106 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__flds_type_of') with nowait goto skip_fn__flds_type_of end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__flds_type_of') with nowait if exists( select top 1 null from sys.objects where name='fn__flds_type_of' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__flds_type_of] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:151106\s.zaglio: added collate database_default v:111205\s.zaglio: added ?varchar(max) v:100710\s.zaglio: orderred by number v:100228\s.zaglio: a remake more simple & faster (as fn__flds_convert) v:091018\s.zaglio: a bug on double size of nvarchar v:090916\S.Zaglio: a better managemnt of temp tables v:090331\S.Zaglio: added manage of ## tables v:090202\S.Zaglio: return a series of field''s types of table t: print dbo.fn__flds_type_of(''cfg'',''|'',null) --> name and id and xtype ... t: create table tst_fn_flds( i int, r real, v varchar(10), nv nvarchar(10), s sysname, n numeric(2,1), vcmax nvarchar(max), ex int) select * into #tst_fn_flds from tst_fn_flds print dbo.fn__flds_type_of(''tst_fn_flds'','','',''ex'') print dbo.fn__flds_type_of(''#tst_fn_flds'','','',null) drop table #tst_fn_flds drop table tst_fn_flds */ CREATE function [dbo].[fn__flds_type_of](@tbl sysname, @seps nvarchar(32)='','',@excludes sysname='''') returns nvarchar(4000) as begin declare @cols nvarchar(4000),@db sysname,@obj sysname,@i int declare @ex table([name] sysname) if @seps is null select @seps='','' -- print parsename(''[db..obj]'',1) -- print parsename(''db..[obj]'',1) select @db=parsename(@tbl,3) select @obj=parsename(@tbl,1) if left(@obj,1)=''#'' collate database_default select @tbl=''tempdb..''+@obj if not @excludes is null insert @ex select token from dbo.fn__str_table(@excludes,@seps) if left(@obj,1)=''#'' collate database_default select @cols =coalesce( @cols+ @seps, '''') + t.name +case -- select * from systypes when t.xusertype in (175,239,231,167) --char,nchar,nvc,vc then ''('' + case when c.prec=-1 then ''max'' else cast(c.prec as nvarchar) end + '')'' -- (@len/case --when left(@column,1) =''n'' --then 2 else 1 end) as nvarchar) + '') '' when t.xusertype in (106,108) then ''('' + cast(c.prec as nvarchar)+'',''+ cast(c.scale as nvarchar)+'') '' else '''' end from tempdb..syscolumns c join tempdb..systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@tbl) and not c.name in (select [name] collate database_default from @ex) order by c.number,c.colorder else select @cols =coalesce( @cols+ @seps, '''') + t.name +case -- select * from systypes when t.xusertype in (175,239,231,167) --char,nchar,nvc,vc then ''('' + case when c.prec=-1 then ''max'' else cast(c.prec as nvarchar) end + '')'' -- (@len/case --when left(@column,1) =''n'' --then 2 else 1 end) as nvarchar) + '') '' when t.xusertype in (106,108) then ''('' + cast(c.prec as nvarchar)+'',''+ cast(c.scale as nvarchar)+'') '' else '''' end from syscolumns c join systypes t on c.xusertype=t.xusertype where c.[id]=object_id(@tbl) and not c.name in (select [name] collate database_default from @ex) order by c.number,c.colorder return @cols end -- fn__flds_type_of' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__flds_type_of: -- ================================================================== fn__format select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__format',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130510 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__format') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__format') with nowait goto skip_fn__format end if @ver>130510 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__format') with nowait goto skip_fn__format end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__format') with nowait if exists( select top 1 null from sys.objects where name='fn__format' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__format] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,io v:130510\s.zaglio: added 02 begin select @i=cast(substring(@fmt,3,4) as int) select @ret=convert(nvarchar(4000), round(cast(@val as float),@i)*power(10,@i) ) end else select @ret=convert(nvarchar(4000),cast(@val as bigint)) select @ret=replicate(''0'',@len-len(@ret))+@ret goto ret money_0left_padding: select @ret=convert(nvarchar(4000),cast(@val as money)) select @ret=replicate(''0'',@len-len(@ret))+@ret goto ret -- =================================================== specific char left pad == specific_pad: -- ########################## -- ## -- ## be careful with len('' '')=0 while datalength('' '')=1 -- ## -- ######################################################## -- select dbo.fn__format(''fn__format'',''=< '',80) -- todo: expand formats to: 0<.0, 0<.00, 0<.000 and so on -- todo: expand formats to: 0<,0, 0<,00, 0<,000 and so on -- todo: expand formats to: 0<00, 0<000, to multiply x XXX and remove decimal sign select @ret=convert(nvarchar(4000),@val), @c=substring(@fmt,3,1), @lc=datalength(@c),@lret=len(@ret) if @lc=0 select @ret=replicate( substring(@fmt,1,1), @len-@lret )+@ret else select @ret=replicate( substring(@fmt,1,1), @len-(@lret+ case when @c='' '' then 1 else @lc end) )+@c+@ret goto ret -- =================================================== normalize anphanumeric == alphanumeric: select @ret=convert(nvarchar(4000),@val) select @l=len(@ret) while @l>0 if not substring(@ret,@l,1) like ''[a-zA-Z0-9]'' select @ret=stuff(@ret,@l,1,''_''),@l=@l-1 else select @l=@l-1 if @fmt=''ANs'' begin while charindex(''__'',@ret)>0 select @ret=replace(@ret,''__'',''_'') select @i=1,@l=len(@ret) while substring(@ret,@i,1)=''_'' select @i=@i+1 while substring(@ret,@l,1)=''_'' select @l=@l-1 select @ret=substring(@ret,@i,@l-@i+1) end goto ret -- ========================================================= replaces accents == replace_accents: -- select dbo.fn__format(''a.é.É.t.è.ù.õ.Ö.Ì.ï.ŝ.s'',''^'',default) /* declare @c nvarchar(2),@val sql_variant,@tmp sysname,@ret sysname,@l int,@i int select @val=''é.É.t.è.ù.õ.Ö.Ì.ï'' */ declare @cc varbinary(8), @acc varbinary(256),@accd varbinary(256), @rep nvarchar(128),@repd nvarchar(128),@w int /* ÂÃÄÀÁÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĒřŠŝş öèéòìàù ĀāĒóôåæ ÀÁÆËÏÍÌ çćĉřŠŝş'' ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöùúûüýþÿĀāĂ㥹ĆćĈĉĊċČč ĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœ ŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƏƒƠơƯưǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǺǻǼǽǾǿØ */ select @w=len(cast(N'' '' as varbinary(8))), @tmp=convert(nvarchar(4000),@val), @ret='''',@i=1,@l=len(@tmp), /* method: Research done by position: 4 to the position of @ acc (Ç) is the rep of @ 4 (C) */ -- @acc contains accented characters to be replaced by individual -- 1 2 3 4 5 -- 012345678901234567890123456789012345678901234567890 @acc=cast(N''ÂÃÅÇÊËÎÐÑÔÕØÛÝÞßâãåçêëîðñôõøûýþĀāĒřŠŝş°¦ª'' as varbinary(256)), @rep= N''AAACEEIDNOOOUYBBaaaceeionooouybAaErSss.|a'', -- @accd contains accented characters to be replaced by double -- 1 2 3 -- 0123456789012345678901234567890 @accd=cast(N''ÄÀÁÆÈÉÌÍÏÒÓÖÙÚÜàáäæèéìíïòóöùúü'' as varbinary(256)), -- 1 2 3 -- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 @repd= N''AEA''''A''''AEE''''E''''I''''I''''IIO''''O''''OEU''''U''''UEa''''a''''aeaee''''e''''i''''i''''iio''''o''''oeu''''u''''ue'' if (@tmp like ''%[''+cast(@acc as nvarchar(128))+cast(@accd as nvarchar(128))+'']%'' ) while @i<=@l begin select @c=substring(@tmp,@i,1), @cc=cast(@c as varbinary(4)), @i=@i+1 -- exec sp__printf ''cc=%s'',@cc select @p=charindex(@cc,@acc) if @p=0 begin select @p=charindex(@cc,@accd) if @p>0 select @c=substring(@repd,@p,2) end else select @c=substring(@rep,@p/@w+1,1) select @ret=@ret+@c -- exec sp__printf ''c=%s; p=%d'',@c,@p end -- while else select @ret=@tmp -- print @ret goto ret -- ================================================================ verbalize == verbalize: /* originally from: http://www.novicksoftware.com/udfofweek/Vol2/T-SQL-UDF-Vol-2-Num-9-udf_Num_ToWords.htm */ declare @inputnumber varchar(38) declare @numberstable table (number char(2), word varchar(10)) declare @length int declare @counter int declare @loops int declare @position int declare @chunk char(3) -- for chunks of 3 numbers declare @tensones char(2) declare @hundreds char(1) declare @tens char(1) declare @ones char(1) declare @number numeric (38, 0) -- input number with as many as 18 digits select @number=convert(numeric(38,0),@val) if @number = 0 return ''zero'' -- initialize the variables select @inputnumber = convert(varchar(38), @number) , @ret = '''' , @counter = 1 select @length = len(@inputnumber) , @position = len(@inputnumber) - 2 , @loops = len(@inputnumber)/3 -- make sure there is an extra loop added for the remaining numbers if len(@inputnumber) % 3 <> 0 set @loops = @loops + 1 -- insert data for the numbers and words insert into @numberstable select ''00'', '''' union all select ''01'', ''one'' union all select ''02'', ''two'' union all select ''03'', ''three'' union all select ''04'', ''four'' union all select ''05'', ''five'' union all select ''06'', ''six'' union all select ''07'', ''seven'' union all select ''08'', ''eight'' union all select ''09'', ''nine'' union all select ''10'', ''ten'' union all select ''11'', ''eleven'' union all select ''12'', ''twelve'' union all select ''13'', ''thirteen'' union all select ''14'', ''fourteen'' union all select ''15'', ''fifteen'' union all select ''16'', ''sixteen'' union all select ''17'', ''seventeen'' union all select ''18'', ''eighteen'' union all select ''19'', ''nineteen'' union all select ''20'', ''twenty'' union all select ''30'', ''thirty'' union all select ''40'', ''forty'' union all select ''50'', ''fifty'' union all select ''60'', ''sixty'' union all select ''70'', ''seventy'' union all select ''80'', ''eighty'' union all select ''90'', ''ninety'' while @counter <= @loops begin -- get chunks of 3 numbers at a time, padded with leading zeros set @chunk = right(''000'' + substring(@inputnumber, @position, 3), 3) if @chunk <> ''000'' begin select @tensones = substring(@chunk, 2, 2) , @hundreds = substring(@chunk, 1, 1) , @tens = substring(@chunk, 2, 1) , @ones = substring(@chunk, 3, 1) -- if twenty or less, use the word directly from @numberstable if convert(int, @tensones) <= 20 or @ones=''0'' begin set @ret = (select word from @numberstable where @tensones = number) + case @counter when 1 then '''' -- no name when 2 then '' thousand '' when 3 then '' million '' when 4 then '' billion '' when 5 then '' trillion '' when 6 then '' quadrillion '' when 7 then '' quintillion '' when 8 then '' sextillion '' when 9 then '' septillion '' when 10 then '' octillion '' when 11 then '' nonillion '' when 12 then '' decillion '' when 13 then '' undecillion '' else '''' end + @ret end else begin -- break down the ones and the tens separately set @ret = '' '' + (select word from @numberstable where @tens + ''0'' = number) + ''-'' + (select word from @numberstable where ''0''+ @ones = number) + case @counter when 1 then '''' -- no name when 2 then '' thousand '' when 3 then '' million '' when 4 then '' billion '' when 5 then '' trillion '' when 6 then '' quadrillion '' when 7 then '' quintillion '' when 8 then '' sextillion '' when 9 then '' septillion '' when 10 then '' octillion '' when 11 then '' nonillion '' when 12 then '' decillion '' when 13 then '' undecillion '' else '''' end + @ret end -- now get the hundreds if @hundreds <> ''0'' begin set @ret = (select word from @numberstable where ''0'' + @hundreds = number) + '' hundred '' + @ret end end select @counter = @counter + 1 , @position = @position - 3 end -- remove any double spaces set @ret = ltrim(rtrim(replace(@ret, '' '', '' ''))) set @ret = upper(left(@ret, 1)) + substring(@ret, 2, 4000) goto ret -- ============================================================ string format == string_format: declare @nc nchar,@mtpl nvarchar(64) select @i=2,@l=len(@fmt), @mtpl=''1234567890abcdefghijklmnopqrsxyvwz'', @ret='''',@tmp=cast(@val as nvarchar(4000)) while (@i<=@l) select @nc=substring(@fmt,@i,1), @p=charindex(@nc,@mtpl), @ret=@ret+case @p when 0 then @nc else substring(@tmp,@p,1) end, @i=@i+1 goto ret -- if not managed type select @ret=left(convert(nvarchar(4000),@val),@len) ret: return @ret end -- fn__format' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__format: -- ============================================================== fn__global_get select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__global_get',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080402 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__global_get') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__global_get') with nowait goto skip_fn__global_get end if @ver>080402 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__global_get') with nowait goto skip_fn__global_get end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__global_get') with nowait if exists( select top 1 null from sys.objects where name='fn__global_get' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__global_get] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080402\S.Zaglio: read from a registry (of MSSQLServer\MyGlobalVars branch) the value */ CREATE function fn__global_get(@variable sysname) returns nvarchar(4000) as begin declare @value nvarchar(4000) EXECUTE master..xp_regread ''HKEY_LOCAL_MACHINE'',''SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\MyGlobalVars'',@variable,@value out return @value end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__global_get: -- ============================================================== fn__global_set select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__global_set',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080402 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__global_set') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__global_set') with nowait goto skip_fn__global_set end if @ver>080402 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__global_set') with nowait goto skip_fn__global_set end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__global_set') with nowait if exists( select top 1 null from sys.objects where name='fn__global_set' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__global_set] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080402\S.Zaglio: read/write from a registry (of MSSQLServer\MyGlobalVars branch) the value t:print dbo.fn__global_set(''test'',''test value'') print dbo.fn__global_get(''test'') */ CREATE function [dbo].[fn__global_set](@variable sysname,@value nvarchar(4000)) returns nvarchar(4000) as begin declare @var sysname,@key sysname select @key=''SOFTWARE\Microsoft\MSSQLServer\MSSQLServer'', @var=''fgv_''+@variable EXECUTE master..xp_regwrite ''HKEY_LOCAL_MACHINE'',@key,@var,''REG_SZ'',@value select @value=null EXECUTE master..xp_regread ''HKEY_LOCAL_MACHINE'',@key,@var,@value out return @value end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__global_set: -- ============================================================== fn__global_var select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__global_var',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080402 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__global_var') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__global_var') with nowait goto skip_fn__global_var end if @ver>080402 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__global_var') with nowait goto skip_fn__global_var end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__global_var') with nowait if exists( select top 1 null from sys.objects where name='fn__global_var' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__global_var] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080402\S.Zaglio: read/write/delete a registry (of MSSQLServer\MyGlobalVars branch) with value t:print dbo.fn__global_var(''test'',''test value'') print dbo.fn__global_var(''test'',''test 1'') print dbo.fn__global_var(''test'',null) t: DECLARE @AuditLevel int EXEC master..xp_regread @rootkey=''HKEY_LOCAL_MACHINE'', @key=''SOFTWARE\Microsoft\MSSQLServer\MSSQLServer'', @value_name=''AuditLevel'', @value=@AuditLevel OUTPUT SELECT @AuditLevel */ CREATE function [dbo].[fn__global_var](@variable sysname,@value nvarchar(4000)) returns nvarchar(4000) as begin declare @var sysname,@key sysname select @key=''SOFTWARE\Microsoft\MSSQLServer\MSSQLServer'', @variable=''fgv_''+@variable if @value is null begin EXECUTE master..xp_regdeletevalue ''HKEY_LOCAL_MACHINE'',@var,@variable return null end declare @old_value nvarchar(4000) EXECUTE master..xp_regread ''HKEY_LOCAL_MACHINE'',@key,@variable,@old_value out if @old_value is null begin EXECUTE master..xp_regwrite ''HKEY_LOCAL_MACHINE'',@key,@variable,''REG_SZ'',@value EXECUTE master..xp_regread ''HKEY_LOCAL_MACHINE'',@key,@variable,@value out return @value end return @old_value end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__global_var: -- =========================================================== fn__group_version select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__group_version',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120802.1100 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__group_version') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__group_version') with nowait goto skip_fn__group_version end if @ver>120802.1100 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__group_version') with nowait goto skip_fn__group_version end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__group_version') with nowait if exists( select top 1 null from sys.objects where name='fn__group_version' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__group_version] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:script,version,group v:120802.1100\s.zaglio: return last version of a group t:select dbo.fn__group_version(''utility'') -- 4 secs reduced to 2 */ CREATE function fn__group_version(@grp sysname) returns sysname as begin declare @t table(id int,tag char,val sysname,primary key(id,tag)) insert @t(id,tag,val) select obj_id,tag,val1 from fn__script_info(default,''rvg'',0) a where not tag is null select @grp=max(a.val) from @t a join @t b on a.id=b.id and a.tag!=''g'' and b.tag=''g'' return @grp end -- fn__group_version' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__group_version: -- ==================================================================== fn__hash select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__hash',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130707 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__hash') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__hash') with nowait goto skip_fn__hash end if @ver>130707 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__hash') with nowait goto skip_fn__hash end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__hash') with nowait if exists( select top 1 null from sys.objects where name='fn__hash' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__hash] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:hash,md5,sha1,hashbytes,limits,8000,chars,len v:130707\s.zaglio: bypasses the limit of 8000 bytes of MS hashbytes c:originally from fn_hashbytesMAX of Brandon Galderisi t: select dbo.fn__hash(cast(''test'' as varbinary(max)),''md5'') -- 0x8706F8479081122D32400F2E681D26C4 select dbo.fn__hash(cast(N''test'' as varbinary(max)),''md5'') -- 0x2BC0BA5B64772F46C3876E043FBF6775 t:select dbo.fn__script_sign(''fn__hash'',default) */ CREATE function dbo.fn__hash( @data varbinary(max), @algo varchar(10) ) returns varbinary(8000) as begin declare @concat varchar(max),@hash varbinary(8000) ;with a as (select 1 as n union all select 1) -- 2 ,b as (select 1 as n from a ,a a1) -- 4 ,c as (select 1 as n from b ,b b1) -- 16 ,d as (select 1 as n from c ,c c1) -- 256 ,e as (select 1 as n from d ,d d1) -- 65,536 ,f as (select 1 as n from e ,e e1) -- 4,294,967,296=17+trillion chrs ,factored as (select row_number() over (order by n) rn from f) ,factors as (select rn,(rn*4000)+1 factor from factored) select @concat = cast(( select right(sys.fn_varbintohexstr ( hashbytes(@algo, substring(@data, factor - 4000, 4000)) ) , 40) + '''' from factors where rn <= ceiling(datalength(@data)/(4000.0)) for xml path('''') ) as nvarchar(max)) if len(@concat)>8000 select @hash=dbo.fn__hash(cast(@concat as varbinary(max)),@algo) else select @hash=hashbytes(@algo,@concat) return @hash end -- fn__hash' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__hash: -- ===================================================================== fn__hex select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__hex',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130929 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__hex') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__hex') with nowait goto skip_fn__hex end if @ver>130929 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__hex') with nowait goto skip_fn__hex end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__hex') with nowait if exists( select top 1 null from sys.objects where name='fn__hex' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__hex] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility c:http://blogs.msdn.com/b/sqltips/archive/2008/07/02/converting-from-hex-string-to-varbinary-and-vice-versa.aspx v:130929\s.zaglio: sys.fn_varbintohexstr is too slow with big data v:130707\s.zaglio: added alias tag v:100805\s.zaglio: managed null @value v:091018\s.zaglio: convert a binary value into a hex string t: declare @s sysname set @s=''hello world!!''+char(13)+char(10) print dbo.fn__hex(convert(varbinary(128),@s)) 0x680065006c006c006f00200077006f0072006c006400210021000d000a00 */ CREATE function [dbo].[fn__hex] ( @value varbinary(max) ) returns varchar(max) as begin return ''0x'' + cast('''' as xml).value(''xs:hexBinary(sql:variable("@value") )'', ''varchar(max)''); end -- fn__hex' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__hex: -- ================================================================= fn__hex2bin select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__hex2bin',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130228 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__hex2bin') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__hex2bin') with nowait goto skip_fn__hex2bin end if @ver>130228 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__hex2bin') with nowait goto skip_fn__hex2bin end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__hex2bin') with nowait if exists( select top 1 null from sys.objects where name='fn__hex2bin' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__hex2bin] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130228\s.zaglio: convert a hex string to binary t:select dbo.fn__hex2bin(''01234ab'') -- return null t:select dbo.fn__hex2bin(''0x1234ab'') -- return 0x1234AB t:select dbo.fn__hex2bin(''1234ab'') -- return 0x1234AB */ CREATE function fn__hex2bin( @hex varchar(max) ) returns varbinary(max) as begin return(select cast('''' as xml).value(''xs:hexBinary( substring(sql:variable("@hex"), sql:column("t.pos")) )'', ''varbinary(max)'') from (select case substring(@hex, 1, 2) when ''0x'' then 3 else 0 end) as t(pos)) end -- fn__hex2bin' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__hex2bin: -- ================================================================= fn__hex2int select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__hex2int',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110627 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__hex2int') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__hex2int') with nowait goto skip_fn__hex2int end if @ver>110627 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__hex2int') with nowait goto skip_fn__hex2int end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__hex2int') with nowait if exists( select top 1 null from sys.objects where name='fn__hex2int' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__hex2int] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110627\s.zaglio:convert hex to int t:print dbo.fn__hex2int(''0x80000005'') -- -2147483643 t:print dbo.fn__hex2int(''0x8000005'') -- 134217733 */ CREATE function fn__hex2int(@v varchar(16)) returns int as begin if left(@v,2)!=''0x'' return null else select @v=upper(substring(@v,3,8)) -- declare @v varchar(10) select @v=''80000005'' declare @vc as varchar(4),@i int,@cl char,@ch char select @vc='''',@i=len(@v) if @i%2=1 select @v=''0''+@v,@i=@i+1 -- exec sp__printf ''@i=%d @v=%s'',@i,@v while (@i>0) begin select @ch=substring(@v,@i-1,1),@cl=substring(@v,@i,1), @vc=char( case when @cl between ''0'' and ''9'' then ascii(@cl)-48 when @cl between ''A'' and ''F'' then ascii(@cl)-55 end + case when @ch between ''0'' and ''9'' then (ascii(@ch)-48)*16 when @ch between ''A'' and ''F'' then (ascii(@ch)-55)*16 end )+@vc, @i=@i-2 -- exec sp__printf ''@cl=%s @ch=%s @i=%d @vc=%s'',@cl,@ch,@i,@vc end return cast(cast(@vc as binary(4)) as int) end -- fn__hex2int' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__hex2int: -- ================================================================== fn__inject select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__inject',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080414 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__inject') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__inject') with nowait goto skip_fn__inject end if @ver>080414 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__inject') with nowait goto skip_fn__inject end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__inject') with nowait if exists( select top 1 null from sys.objects where name='fn__inject' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__inject] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080414\S.Zaglio:inculate a string or sql */ CREATE function [dbo].[fn__inject]( @sql nvarchar(4000) ) returns nvarchar(4000) AS begin set @sql=replace(@sql,'''''''','''''''''''') return @sql end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__inject: -- ================================================================== fn__inlike select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__inlike',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100228 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__inlike') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__inlike') with nowait goto skip_fn__inlike end if @ver>100228 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__inlike') with nowait goto skip_fn__inlike end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__inlike') with nowait if exists( select top 1 null from sys.objects where name='fn__inlike' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__inlike] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100228\s.zaglio: test @s with parts of @likes separated by | t:print dbo.fn__inlike(''me'',''you|me|us'') --> 1 t:print dbo.fn__inlike(''it'',''you|me|us'') --> 0 t:print dbo.fn__inlike(''you'',''your|%me%|us'') --> 0 */ create function fn__inlike(@s nvarchar(4000),@likes nvarchar(4000)) returns bit as begin /* declare @s nvarchar(4000),@likes nvarchar(4000) select @s=''b'',@likes=''a|b|c'' --*/ declare @like nvarchar(4000),@i int,@n int,@noperc bit if charindex(''%'',@s)=0 select @noperc=1 select @i=1,@n=dbo.fn__str_count(@likes,''|'') while (@i<=@n) begin select @like=dbo.fn__str_at(@likes,''|'',@i) if @noperc=1 select @like=''%''+@like+''%'' if @s like @like return 1 select @i=@i+1 end return 0 end -- fn__inlike' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__inlike: -- ================================================================== fn__int2ip select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__int2ip',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120904 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__int2ip') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__int2ip') with nowait goto skip_fn__int2ip end if @ver>120904 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__int2ip') with nowait goto skip_fn__int2ip end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__int2ip') with nowait if exists( select top 1 null from sys.objects where name='fn__int2ip' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__int2ip] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:ip,int,convert v:120904\s.zaglio:from http://www.mssqltips.com/sqlservertip/2535/ t:print dbo.fn__int2ip(167772161) -- 10.0.0.1 */ CREATE function fn__int2ip(@ip bigint) returns varchar(15) as begin declare @octet1 tinyint declare @octet2 tinyint declare @octet3 tinyint declare @octet4 tinyint declare @restofip bigint set @octet1 = @ip / 16777216 set @restofip = @ip - (@octet1 * 16777216) set @octet2 = @restofip / 65536 set @restofip = @restofip - (@octet2 * 65536) set @octet3 = @restofip / 256 set @octet4 = @restofip - (@octet3 * 256) return( convert(varchar, @octet1) + ''.'' + convert(varchar, @octet2) + ''.'' + convert(varchar, @octet3) + ''.'' + convert(varchar, @octet4) ) end -- fn__int2ip' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__int2ip: -- ================================================================== fn__ip2int select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__ip2int',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120904 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__ip2int') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__ip2int') with nowait goto skip_fn__ip2int end if @ver>120904 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__ip2int') with nowait goto skip_fn__ip2int end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__ip2int') with nowait if exists( select top 1 null from sys.objects where name='fn__ip2int' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__ip2int] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:ip,int,convert v:120904\s.zaglio:from http://www.mssqltips.com/sqlservertip/2535/ t:print dbo.fn__ip2int(''10.0.0.1'') */ create function fn__ip2int(@ip varchar(15)) returns bigint -- for future ipv6 as begin return( convert(bigint, parsename(@ip,1)) + convert(bigint, parsename(@ip,2)) * 256 + convert(bigint, parsename(@ip,3)) * 65536 + convert(bigint, parsename(@ip,4)) * 16777216 ) end -- fn__int2ip' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__ip2int: -- =============================================================== fn__isConsole select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isConsole',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131208 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isConsole') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isConsole') with nowait goto skip_fn__isConsole end if @ver>131208 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isConsole') with nowait goto skip_fn__isConsole end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isConsole') with nowait if exists( select top 1 null from sys.objects where name='fn__isConsole' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isConsole] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:is,console,ssms,app_name,test v:131208\s.zaglio:added check of SSDT v:130106.1000\s.zaglio:return 1 if app_name is a console like SSMS t:select dbo.fn__isConsole() */ CREATE function fn__isConsole() returns bit as begin -- works only locally because app_name() of a remote call is -- mssql or ms.client or ... if left(app_name(),39)=''Microsoft SQL Server Management Studio'' or left(app_name(),31)=''Microsoft SQL Server Data Tools'' return 1 return 0 end -- fn__isConsole' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isConsole: -- ================================================================== fn__isGuid select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isGuid',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090807 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isGuid') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isGuid') with nowait goto skip_fn__isGuid end if @ver>090807 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isGuid') with nowait goto skip_fn__isGuid end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isGuid') with nowait if exists( select top 1 null from sys.objects where name='fn__isGuid' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isGuid] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090807\S.Zaglio: added remove of '',",{,} v:090604\S.Zaglio: test a guid c:originally from: http://jesschadwick.blogspot.com/2007/11/safe-handling-of-uniqueidentifier-in.html t: print dbo.fn__isguid(convert(sysname,newid())) t: print dbo.fn__isguid(replace(convert(sysname,newid()),''-'',''_'')) t: print convert(uniqueidentifier,convert(sysname,newid())) */ CREATE function [dbo].[fn__isGuid](@input nvarchar(48)) returns bit as begin declare @isvalidguid bit; set @isvalidguid = 0; select @input=replace(@input, ''-'', '''') select @input=replace(@input, '''''''', '''') select @input=replace(@input, ''"'', '''') select @input=replace(@input, ''{'', '''') select @input=replace(@input, ''}'', '''') set @input = upper(ltrim(rtrim(@input))); if(@input is not null and len(@input) = 32) begin declare @indexchar nchar(1) declare @index int; set @index = 1; while (@index <= 32) begin set @indexchar = substring(@input, @index, 1); if (isnumeric(@indexchar) = 1 or @indexchar in (''a'', ''b'', ''c'', ''d'', ''e'', ''f'')) set @index = @index + 1; else break; end if(@index = 33) set @isvalidguid = 1; end return @isvalidguid; end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isGuid: -- =================================================================== fn__isJob select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isJob',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110321 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isJob') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isJob') with nowait goto skip_fn__isJob end if @ver>110321 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isJob') with nowait goto skip_fn__isJob end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isJob') with nowait if exists( select top 1 null from sys.objects where name='fn__isJob' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isJob] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110321\s.zaglio:added italian "SERVIZIO DI RETE" v:110213\s.zaglio:added SQLServerAgentSVC and exclusion of instance v:101211\s.zaglio:return 1 if the @spid is executed from a job */ CREATE function fn__isJob(@spid int) returns bit as begin if exists( select spid,program_name,hostname,nt_username from master..sysprocesses where spid=@spid and left([program_name],8)=''SQLAgent'' and hostname=left(@@servername,len(hostname)) -- istance is not passed and ltrim(rtrim(nt_username)) in (''SYSTEM'',''SQLServerAgentSVC'',''SERVIZIO DI RETE'') ) return 1 return 0 end -- fn__isJob' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isJob: -- ================================================================ fn__islocked select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__islocked',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__islocked') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__islocked') with nowait goto skip_fn__islocked end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__islocked') with nowait goto skip_fn__islocked end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__islocked') with nowait if exists( select top 1 null from sys.objects where name='fn__islocked' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__islocked] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091018\s.zaglio: added @db_id (sp__find ''fn__islocked'') v:090910\s.zaglio: check if an object is locked t:print dbo.fn__islocked(db_id(''msdb''),object_id(''sysobjects'')) */ CREATE function [dbo].[fn__islocked](@id int,@db_id int) returns bit as begin declare @locked bit select @locked=0 if exists( -- sp_lock select null /*convert (smallint, req_spid) As spid, rsc_dbid As dbid, rsc_objid As ObjId, rsc_indid As IndId, substring (v.name, 1, 4) As Type, substring (rsc_text, 1, 16) as Resource, substring (u.name, 1, 8) As Mode, substring (x.name, 1, 5) As Status */ from master.dbo.syslockinfo, master.dbo.spt_values v, master.dbo.spt_values x, master.dbo.spt_values u where rsc_dbid=@db_id and rsc_objid=@id and master.dbo.syslockinfo.rsc_type = v.number and v.type = ''LR'' and master.dbo.syslockinfo.req_status = x.number and x.type = ''LS'' and master.dbo.syslockinfo.req_mode + 1 = u.number and u.type = ''L'' /*order by spid*/ ) select @locked=1 return @locked end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__islocked: -- =============================================================== fn__isMSSQL2K select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isMSSQL2K',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110629 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isMSSQL2K') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isMSSQL2K') with nowait goto skip_fn__isMSSQL2K end if @ver>110629 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isMSSQL2K') with nowait goto skip_fn__isMSSQL2K end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isMSSQL2K') with nowait if exists( select top 1 null from sys.objects where name='fn__isMSSQL2K' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isMSSQL2K] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110629\s.zaglio: optimized v:100919\s.zaglio: more compatible mssql2k v:100204\s.zaglio: return 1 if this is mssql 2000 t:select @@version,dbo.fn__isMSSQL2K(),substring(@@version,23,4) t: declare @d datetime,@i int,@r nvarchar(4) select @i=10000 exec sp__elapsed @d out,''init'' while @i>0 select @r=substring(@@version,8,4),@i=@i-1 -- faster exec sp__elapsed @d out,''after @@ver'' select @i=10000 while @i>0 select @r=substring(cast(serverproperty(''productversion'') as sysname),1,1),@i=@i-1 exec sp__elapsed @d out,''after prop'' */ CREATE function fn__isMSSQL2K() returns bit as begin if substring(@@version,23,4) in (''2000'',''000 '') return 1 -- Microsoft SQL Server 2000 - 8.00.2039 ... /* ''Microsoft SQL Server 2000'', ''Microsoft SQL Server 200'' ) return 1 */ return 0 end -- fn__isMSSQL2K()' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isMSSQL2K: -- =============================================================== fn__isnumeric select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isnumeric',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130729 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isnumeric') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isnumeric') with nowait goto skip_fn__isnumeric end if @ver>130729 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isnumeric') with nowait goto skip_fn__isnumeric end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isnumeric') with nowait if exists( select top 1 null from sys.objects where name='fn__isnumeric' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isnumeric] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility c:http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html c:http://codecorner.galanter.net/2009/04/03/tsql-isnumeric-function-returns-false-positives/ v:130729\s.zaglio:new concept v:120305\s.zaglio:bug near hexadecimal v:120213\s.zaglio:added hexadecimal v:110627\s.zaglio:extend mssql isnumeric t:print dbo.fn__isnumeric(''test test'') -- 0 t:print dbo.fn__isnumeric(0x80035C56) -- 0 t:print dbo.fn__isnumeric(''0xfffe'') -- 1 t:print dbo.fn__isnumeric(''0xfffx'') -- 0 t:print dbo.fn__isnumeric(''0xfx00'') -- 0 t:print dbo.fn__isnumeric(''0.123'') -- 1 t:select isnumeric(''0.123.23''),dbo.fn__isnumeric(''0.123.23'') print convert(float,''0.123.23'') t:print isnumeric(''0,123'') print convert(float,''0,123'') -- error t:print dbo.fn__isnumeric(''0,123,23'') -- 0 todo:manage numbers with ,,,... */ CREATE function fn__isnumeric(@vs nvarchar(4000)) returns bit as begin declare @i int,@n int if left(@vs,2)=''0x'' if substring(@vs,3,4000) like ''%[^0-9abcdef]%'' return 0 else return 1 if charindex(''e'', @vs)!=0 return isnumeric(@vs) else return isnumeric(@vs+''e0'') return null end -- fn__isnumeric' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isnumeric: -- ================================================================ fn__isRemote select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__isRemote',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120103 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__isRemote') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__isRemote') with nowait goto skip_fn__isRemote end if @ver>120103 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__isRemote') with nowait goto skip_fn__isRemote end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__isRemote') with nowait if exists( select top 1 null from sys.objects where name='fn__isRemote' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__isRemote] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120103\s.zaglio:seems to works r:101211\s.zaglio:return 1 if the sp is called from a remote server c:replace @@remserver */ CREATE function fn__isRemote(@spid int) returns bit as begin if exists( select null from master..sysprocesses where spid=@spid and app_name()=''Microsoft SQL Server'' -- and left([program_name],8)=''SQLAgent'' -- and hostname=@@servername and nt_username='''' and nt_domain='''' ) return 1 return 0 end -- fn__isRemote' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__isRemote: -- ==================================================================== fn__left select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__left',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081010 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__left') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__left') with nowait goto skip_fn__left end if @ver>081010 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__left') with nowait goto skip_fn__left end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__left') with nowait if exists( select top 1 null from sys.objects where name='fn__left' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__left] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:081010\S.Zaglio: extend left with negative len t:print dbo.fn__left(''without last char*'',-1) -->without last char */ create function fn__left(@s nvarchar(4000),@l smallint) returns nvarchar(4000) as begin declare @s1 nvarchar(4000) if @s is null return null if @l=0 return '''' if @l>0 set @s1=left(@s,@l) else set @s1=left(@s,len(@s)+@l) return @s1 end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__left: -- ================================================================ fn__max_date select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__max_date',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121023 begin if @aut!='M.Guion' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__max_date') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__max_date') with nowait goto skip_fn__max_date end if @ver>121023 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__max_date') with nowait goto skip_fn__max_date end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__max_date') with nowait if exists( select top 1 null from sys.objects where name='fn__max_date' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__max_date] begin try exec dbo.sp_executesql @statement = N'/* leave this g:utility v:121023\M.Guion: restituisce la maggiore tra due date */ CREATE FUNCTION [dbo].[fn__max_date] ( @date1 datetime, @date2 datetime ) RETURNS datetime AS BEGIN IF (ISNULL(@date1, ''19000101'') >= isnull(@date2, ''19000101'')) RETURN @date1 RETURN @date2 END' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__max_date: -- =================================================================== fn__md5_r select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__md5_r',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110422 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__md5_r') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__md5_r') with nowait goto skip_fn__md5_r end if @ver>110422 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__md5_r') with nowait goto skip_fn__md5_r end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__md5_r') with nowait if exists( select top 1 null from sys.objects where name='fn__md5_r' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__md5_r] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110422\s.zaglio: used by sp__md5 or fn__md5 */ create function [dbo].[fn__md5_r](@r SMALLINT, @a bigint, @b bigint, @c bigint, @d bigint, @x bigint, @s bigint, @t bigint ) returns bigint as begin declare @r0 bigint, @r1 bigint if @r=0 begin select @r0 = ( ( ( @c ^ @d ) & @b ) ^ @d ) select @r1 = ( @a + @r0 + @x + @t ) & 0x000000000ffffffff select @r0 = ( ( @r1 * @s ) | cast( @r1 * @s / 4294967296 as bigint ) + @b ) & 0x000000000ffffffff end if @r=1 begin select @r0 = ( ( @b ^ @c ) & @d ) ^ @c select @r1 = ( @a + @r0 + @x + @t ) & 0x000000000ffffffff select @r0 = ( ( @r1 * @s ) | cast( @r1 * @s / 4294967296 as bigint ) + @b ) & 0x000000000ffffffff end if @r=2 begin select @r0 = @b ^ @c ^ @d select @r1 = ( @a + @r0 + @x + @t ) & 0x00000000ffffffff select @r0 = ( ( @r1 * @s ) | cast( @r1 * @s / 4294967296 as bigint ) + @b ) & 0x00000000ffffffff end if @r=3 begin select @r0 = ( ( ~@d ) | @b ) ^@c select @r1 = ( @a + @r0 + @x + @t ) & 0x00000000ffffffff select @r0 = ( ( @r1 * @s ) | cast( @r1 * @s / 4294967296 as bigint ) + @b ) & 0x00000000ffffffff end return @r0 end -- fn__md5_r' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__md5_r: -- ============================================================= fn__object_type select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__object_type',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090606 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__object_type') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__object_type') with nowait goto skip_fn__object_type end if @ver>090606 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__object_type') with nowait goto skip_fn__object_type end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__object_type') with nowait if exists( select top 1 null from sys.objects where name='fn__object_type' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__object_type] begin try exec dbo.sp_executesql @statement = N'/* leave this v:090606\S.Zaglio: return object definition (int,varchar,etc. if column; V,C,U,etc. if not) g:utility t:print dbo.fn__object_type(''sysobjects'') t:print dbo.fn__object_type(''sysobjects.name'') t:print dbo.fn__object_type(''test.txt'') */ CREATE function [dbo].[fn__object_type](@name sysname) returns sysname as begin declare @obj sysname declare @col sysname declare @type sysname select @obj=dbo.fn__str_at(@name,''.'',1), @col=dbo.fn__str_at(@name,''.'',2) if @col is null select top 1 @type=xtype from sysobjects where id=object_id(@name) else select top 1 @type=t.name from syscolumns c inner join systypes t on c.xusertype=t.xusertype where c.id=object_id(@obj) and c.name=@col return @type end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__object_type: -- ============================================================== fn__occurrence select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__occurrence',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100228 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__occurrence') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__occurrence') with nowait goto skip_fn__occurrence end if @ver>100228 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__occurrence') with nowait goto skip_fn__occurrence end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__occurrence') with nowait if exists( select top 1 null from sys.objects where name='fn__occurrence' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__occurrence] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100228\s.zaglio: count occurrence of @seq in @s todo:deprecate to fn__occurrences t:print dbo.fn__occurrence('''','','') --> 0 t:print dbo.fn__occurrence(''a,b,c'','','') --> 2 t:print dbo.fn__occurrence(''a'','','') --> 0 t:print dbo.fn__occurrence(''a,b'','','') --> 1 */ CREATE function [dbo].[fn__occurrence](@s nvarchar(4000),@seq nvarchar(32)) returns int as begin declare @i int set @i=0 declare @n int set @n=0 if @s is null return null if @s='''' return 0 declare @k int set @k=len(@seq) select @i=charindex(@seq,@s) while @i>0 begin select @n=@n+1 select @i=charindex(@seq,@s,@i+@k) end -- while return @n end -- fn__occurrence' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__occurrence: -- =========================================================== fn__plan_calendar select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__plan_calendar',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121118 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__plan_calendar') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__plan_calendar') with nowait goto skip_fn__plan_calendar end if @ver>121118 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__plan_calendar') with nowait goto skip_fn__plan_calendar end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__plan_calendar') with nowait if exists( select top 1 null from sys.objects where name='fn__plan_calendar' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__plan_calendar] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,plan k:plan,calendar,planning r:121118\s.zaglio: store a date into the plan calendar strtucture t:sp__plan_calendar_test */ CREATE function fn__plan_calendar( @dt datetime, @days nvarchar(24) -- 12 int:bit0=01/01 ) returns nvarchar(24) as begin /* declare @dt datetime, @days varchar(48) -- 12 int:bit0=01/01 select @dt=''2012-01-02'', -- ydm @days='''' */ declare @l int, @pmm int, -- byte position of month @dd bigint, @chunk binary(4) -- days buffer select @l=datalength(@days), @pmm=(month(@dt)-1)*2+1, @dd=power(2,day(@dt)-1) -- select @dt dt,@days days,@l l,@pmm pmm,@dd dd if @l<@pmm+2 select @days=@days+replicate(char(0),@pmm+2-1-@l) select @chunk=cast(substring(@days,@pmm,2) as binary(4))|@dd -- select datalength(@days) len_days,@chunk chunk /* select @days= convert(varbinary(48), stuff( convert(varchar(48),@days), @pmm, 4, convert(varchar(4),@chunk) ) ) */ select @days=substring(@days,1,@pmm-1)+cast(@chunk as nchar(2)) +substring(@days,@pmm+2,48) -- select cast(@days as varbinary(48)) result return @days end -- fn__plan_calendar' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__plan_calendar: -- ================================================================== fn__printf select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__printf',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130725 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__printf') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__printf') with nowait goto skip_fn__printf end if @ver>130725 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__printf') with nowait goto skip_fn__printf end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__printf') with nowait if exists( select top 1 null from sys.objects where name='fn__printf' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__printf] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130725,130724\s.zaglio: a bug in particolar condition from sp__elapsed v:130614\s.zaglio: added %x and varchar max v:110429\s.zaglio: added special case for *binary v:100918\s.zaglio: again better print on small float and real v:100914\s.zaglio: better precision on datetime,real, etc. v:081021\S.Zaglio: corrected bad replace in case @p? contains %s v:080925\S.Zaglio: replace xp_printf because truncate strings to +/-1000 chars v:080515\S.Zaglio: as sp__printf but only for functions debug, don''t print t:sp__printf_test @opt=''run'',@dbg=1 t:print dbo.fn__printf(''test (%s)'',''%drop%'',null,null,null,null,null,null,null,null,null) */ CREATE function fn__printf( @format nvarchar(max), @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @p5 sql_variant=null, @p6 sql_variant=null, @p7 sql_variant=null, @p8 sql_variant=null, @p9 sql_variant=null, @p0 sql_variant=null) returns nvarchar(max) as begin declare @p sql_variant,@s nvarchar(4000), @crlf nvarchar(2),@tab nvarchar(2), @i int,@n int,@type char,@ln int select @crlf=crlf,@tab=tab,@n=1 from fn__sym() select @p1=isnull(@p1,''(null)''), @p2=isnull(@p2,''(null)''), @p3=isnull(@p3,''(null)''), @p4=isnull(@p4,''(null)''), @p5=isnull(@p5,''(null)''), @p6=isnull(@p6,''(null)''), @p7=isnull(@p7,''(null)''), @p8=isnull(@p8,''(null)''), @p9=isnull(@p9,''(null)''), @p0=isnull(@p0,''(null)'') select @format=replace(@format,''%d'',''%s'') select @format=replace(@format,''\n'',@crlf) select @format=replace(@format,''\t'',@tab) select @i=charindex(''%'',@format),@ln=len(@format) while (@i>0) begin select @type=substring(@format,@i+1,1) if @type in (''s'',''x'',''d'') begin select @p=(case @n when 1 then @p1 when 2 then @p2 when 3 then @p3 when 4 then @p4 when 5 then @p5 when 6 then @p6 when 7 then @p7 when 8 then @p8 when 9 then @p9 when 10 then @p0 end) if @type!=''x'' and sql_variant_property(@p,''BaseType'') in (''datetime'',''smalldatetime'') select @s=convert(nvarchar(4000),@p,126) else if @type!=''x'' and sql_variant_property(@p,''BaseType'') in (''real'',''float'') begin select @s=convert(nvarchar(4000),@p,0) if charindex(''e-'',@s)>0 select @s=convert(nvarchar(4000),@p,1) if charindex(''e-'',@s)>0 select @s=convert(nvarchar(4000),@p,2) end else if sql_variant_property(@p,''BaseType'') in (''binary'',''varbinary'') or @type=''x'' select @s=sys.fn_varbintohexstr(convert(varbinary(8000),@p)) else select @s=convert(nvarchar(4000),@p) select @format=left(@format,@i-1)+@s+substring(@format,@i+2,@ln) select @i=@i+len(@s) select @n=@n+1 end else if @type=''%'' select @format=left(@format,@i)+substring(@format,@i+2,@ln), @i=@i+1 else select @i=@i+1 select @i=charindex(''%'',@format,@i) end -- while -- the xp_sprintf truncate to less than 4000 chars -- exec master..xp_sprintf @format out,@format,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p0 return @format end -- fn__printf' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__printf: -- ================================================================== fn__prints select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__prints',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130612 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__prints') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__prints') with nowait goto skip_fn__prints end if @ver>130612 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__prints') with nowait goto skip_fn__prints end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__prints') with nowait if exists( select top 1 null from sys.objects where name='fn__prints' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__prints] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:prints,sp__prints,separator,better,code,read v:130612\s.zaglio: used by sp__prints t:select dbo.fn__prints(''8131009 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__RegexMatch') with nowait goto skip_fn__RegexMatch end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__RegexMatch') with nowait if exists( select top 1 null from sys.objects where name='fn__RegexMatch' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__RegexMatch] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131009\s.zaglio:restyle v:080101\www.simple-talk.com c:probably the best tutorial on the web for regular expressions is on www.regular-expressions.info c:but it is also worth reading implementing real-world data input validation using regular expressions by francis norton c:for an introduction to regular expressions: c:http://www.simple-talk.com/dotnet/.net-framework/implementing-real-world-data-input-validation-using-regular-expressions/ t: -- now, with this routine, we can do some complex input validation --is there a repeating word select dbo.fn__regexmatch(''\b(\w+)\s+\1\b'',''this has has been repeated'')--1 select dbo.fn__regexmatch(''\b(\w+)\s+\1\b'',''this has not been repeated'')--0 --find a word near another word (in this case ''for'' and ''last'' 1 or 2 words apart) select dbo.fn_regexmatch(''\bfor(?:\w+\w+){1,2}?\w+last\b'', ''you have failed me for the last time, admiral'')--1 select dbo.fn__regexmatch(''\bfor(?:\w+\w+){1,2}?\w+last\b'', ''you have failed me for what could be the last time, admiral'')--0 --is this likely to be a valid credit card select dbo.fn__regexmatch(''^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0 [0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13}|(?:2131|1800)\d{11})$'',''4953129482924435'') --is this a valid zip code select dbo.fn__regexmatch(''^[0-9]{5,5}([- ]?[0-9]{4,4})?$'',''02115-4653'') --is this a valid postcode select dbo.fn__regexmatch(''^([gg][ii][rr] 0[aa]{2})|((([a-za-z][0-9]{1,2})|(([a-za-z][a-ha -hj-yj-y][0-9]{1,2})|(([a-za-z][0-9][a-za-z])|([a-za-z][a-ha-hj-yj-y][0-9]?[a-za-z]))) ) {0,1}[0-9][a-za-z]{2})$'',''rg35 2aq'') --is this a valid european date select dbo.fn__regexmatch(''^((((31\/(0?[13578]|1[02]))|((29|30)\/(0?[1,3-9]|1[0-2])))\/(1[ 6-9]|[2-9]\d)?\d{2})|(29\/0?2\/(((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16 |[2468][048]|[3579][26])00))))|(0?[1-9]|1\d|2[0-8])\/((0?[1-9])|(1[0-2]))\/((1[6-9]|[2 -9]\d)?\d{2})) (20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$'',''12/12/2007 20:15:27'') --is this a valid currency value (dollar) select dbo.fn__regexmatch(''^\$(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$'',''$34,000.00'') --is this a valid currency value (sterling) select dbo.fn__regexmatch(''^\£(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$'', ''£34,000.00'') --a valid email address? select dbo.fn__regexmatch(''^(([a-za-z0-9!#\$%\^&\*\{\}''''`\+=-_\|/\?]+(\.[a-za-z0-9!#\$%\^& \*\{\}''''`\+=-_\|/\?]+)*){1,64}@(([a-za-z0-9]+[a-za-z0-9-_]*){1,63}\.)*(([a-za-z0-9]+[a -za-z0-9-_]*){3,63}\.)+([a-za-z0-9]{2,4}\.?)+){1,255}$'',''phil.factor@simple-talk.com'') */ CREATE function dbo.fn__regexmatch ( @pattern nvarchar(2000), @matchstring nvarchar(max)--varchar(8000) got sql server 2000 ) returns int /* the regexmatch returns true or false, indicating if the regular expression matches (part of) the string. (it returns null if there is an error). when using this for validating user input, you''ll normally want to check if the entire string matches the regular expression. to do so, put a caret at the start of the regex, and a dollar at the end, to anchor the regex at the start and end of the subject string. */ -- with this function, the passing back of errors is rudimentary. -- if an ole error occurs, then a null is passed back. as begin declare @objregexexp int, @objerrorobject int, @strerrormessage nvarchar(255), @hr int, @match bit select @strerrormessage = ''creating a regex object'' exec @hr= sp_oacreate ''vbscript.regexp'', @objregexexp out if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''pattern'', @pattern --specifying a case-insensitive match if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''ignorecase'', 1 --doing a test'' if @hr = 0 exec @hr= sp_oamethod @objregexexp, ''test'', @match out, @matchstring if @hr <> 0 begin return null end exec sp_oadestroy @objregexexp return @match end -- fn__regexmatch' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__RegexMatch: -- ============================================================ fn__RegexReplace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__RegexReplace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131009 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__RegexReplace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__RegexReplace') with nowait goto skip_fn__RegexReplace end if @ver>131009 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__RegexReplace') with nowait goto skip_fn__RegexReplace end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__RegexReplace') with nowait if exists( select top 1 null from sys.objects where name='fn__RegexReplace' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__RegexReplace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131009\s.zaglio:restyle v:080101\www.simple-talk.com t: --remove repeated words in text SELECT dbo.fn__RegexReplace(''\b(\w+)(?:\s+\1\b)+'', ''$1'', ''Sometimes I cant help help help stuttering'',1, 1) --find a #comment and add a TSQL -- SELECT dbo.fn__RegexReplace(''#.*'',''--$&'','' # this is a comment first,second,third,fourth'',1,1) --replace a url with an HTML anchor SELECT dbo.fn__RegexReplace( ''\b(https?|ftp|file)://([-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])'', ''$2'', ''There is this amazing site at http://www.simple-talk.com'',1,1) --strip all HTML elements out of a string SELECT dbo.fn__RegexReplace(''<(?:[^>''''"]*|([''''"]).*?\1)*>'', '''',''Simle Talk is wonderful we all love it'',1,1) --import delimited ntext into a database, converting it into insert statements SELECT dbo.fn__RegexReplace( ''([^\|\r\n]+)[|\r\n]+([^\|\r\n]+)[|\r\n]+([^\|\r\n]+)[|\r\n]+([^\|\r\n]+)[|\r\n]+'', ''Insert into MyTable (Firstcol,SecondCol, ThirdCol, Fourthcol) select $1,$2,$3,$4 '',''1|white gloves|2435|24565 2|Sports Shoes|285678|0987 3|Stumps|2845|987 4|bat|29862|4875'',1,1) */ CREATE FUNCTION dbo.fn__RegexReplace ( @pattern nvarchar(255), @replacement nvarchar(255), @Subject nvarchar(4000), @global BIT = 1, @Multiline bit =1 ) returns nvarchar(4000) /*the regexreplace function takes three string parameters. the pattern (the regular expression) the replacement expression, and the subject string to do the manipulation to. the replacement expression is one that can cause difficulties. you can specify an empty string '''' as the @replacement text. this will cause the replace method to return the subject string with all regex matches deleted from it (see "strip all html elements out of a string" below). to re-insert the regex match as part of the replacement, include $& in the replacement text. (see "find a #comment and add a tsql --" below) if the regexp contains capturing parentheses, you can use backreferences in the replacement text. $1 in the replacement ntext inserts the ntext matched by the first capturing group, $2 the second, etc. up to $9. (e.g. see import delimited ntext into a database below) to include a literal dollar sign in the replacements, put two consecutive dollar signs in the string you pass to the replace method.*/ as begin declare @objregexexp int, @objerrorobject int, @strerrormessage nvarchar(255), @substituted nvarchar(4000), @hr int, @replace bit select @strerrormessage = ''creating a regex object'' exec @hr= sp_oacreate ''vbscript.regexp'', @objregexexp out if @hr = 0 select @strerrormessage = ''setting the regex pattern'', @objerrorobject = @objregexexp if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''pattern'', @pattern if @hr = 0 /* by default, the regular expression is case sensitive. set the ignorecase property to true to make it case insensitive. */ select @strerrormessage = ''specifying the type of match'' if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''ignorecase'', 1 if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''multiline'', @multiline if @hr = 0 exec @hr= sp_oasetproperty @objregexexp, ''global'', @global if @hr = 0 select @strerrormessage = ''doing a replacement'' if @hr = 0 exec @hr= sp_oamethod @objregexexp, ''replace'', @substituted out, @subject, @replacement /*if the regexp.global property is false (the default), replace will return the @subject string with the first regex match (if any) substituted with the replacement text. if regexp.global is true, the @subject string will be returned with all matches replaced.*/ if @hr <> 0 begin declare @source nvarchar(255), @description nvarchar(255), @helpfile nvarchar(255), @helpid int execute sp_oageterrorinfo @objerrorobject, @source output, @description output, @helpfile output, @helpid output select @strerrormessage = ''error whilst '' + coalesce(@strerrormessage, ''doing something'') + '', '' + coalesce(@description, '''') return @strerrormessage end exec sp_oadestroy @objregexexp return @substituted end -- fn__RegexReplace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__RegexReplace: -- ========================================================== fn__script_buildin select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__script_buildin',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110916 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__script_buildin') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__script_buildin') with nowait goto skip_fn__script_buildin end if @ver>110916 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__script_buildin') with nowait goto skip_fn__script_buildin end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_buildin') with nowait if exists( select top 1 null from sys.objects where name='fn__script_buildin' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__script_buildin] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110916\s.zaglio:added special case with @usr='''' and @comment='''' v:110824\s.zaglio:added @usr v:110325\s.zaglio:return buildin string for scripts t:select dbo.fn__script_buildin(getdate(),default,default,default) t:select dbo.fn__script_buildin(getdate(),0,''s.zaglio'',''test'') t:select dbo.fn__script_buildin(getdate(),1,'''','''') t:sp__find ''fn__script_buildin'' */ CREATE function fn__script_buildin( @dt datetime, @time int, @usr sysname, @comment sysname ) returns sysname as begin declare @s sysname select @s= convert(sysname,@dt,12)+ case when isnull(@time,1)=1 then ''.''+left(replace(convert(sysname,@dt,8),'':'',''''),4) else '''' end+ case when isnull(@usr,'''')='''' and isnull(@comment,'''')='''' then '''' else ''\''+isnull(@usr,system_user)+ '':''+isnull(@comment,''%unspecified comment%'') end return @s end -- fn__script_buildin' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__script_buildin: -- ============================================================== fn__servername select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__servername',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__servername') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__servername') with nowait goto skip_fn__servername end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__servername') with nowait goto skip_fn__servername end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__servername') with nowait if exists( select top 1 null from sys.objects where name='fn__servername' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__servername] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091018\s.zaglio: added ip recodnize v:090127\S.Zaglio: added domain and now this function check if @svr is local, ignoring the domain if necessary v:081121\S.Zaglio: replace @@servername that can fail with virtual svr name when there is a real svr with same name t: print dbo.fn__servername(null) t: print dbo.fn__servername(''server.domain\instance'') ->server.domain\instance t: print dbo.fn__servername(''server\instance'') ->server\instance t: print dbo.fn__servername(''ip\instance'') ->ip\instance */ CREATE function fn__servername(@svr sysname) returns sysname as begin declare @r sysname -- set @r=coalesce(@@servername,convert(sysname,serverproperty(''servername''))) -- I don''t remember why excluded @@servername declare @key sysname,@domain sysname,@server sysname,@instance sysname,@ip sysname select @ip=dbo.fn__global_get(''server_ip'') SET @key = ''SYSTEM\ControlSet001\Services\Tcpip\Parameters\'' EXEC master..xp_regread @rootkey=''HKEY_LOCAL_MACHINE'', @key=@key,@value_name=''Domain'',@value=@Domain OUTPUT -- SELECT ''Server Name: ''+@@servername + '' Domain Name:''+convert(varchar(100),@Domain) set @server=convert(sysname,serverproperty(''servername'')) declare @i int set @i=charindex(''\'',@server) if @i>0 begin set @instance=substring(@server,@i,len(@server)) set @server=left(@server,@i-1) end else set @instance='''' set @r=@server+coalesce(''.''+@domain,'''')+@instance if not @svr is null begin set @server=replace(@svr,''\'',''%\'') set @ip=@ip+@instance if @r like @server set @r=@svr -- return name witch to check if @svr like @ip set @r=@svr end return @r end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__servername: -- ============================================================== fn__split_part select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__split_part',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120919 begin if @aut!='A.Sirna' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__split_part') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__split_part') with nowait goto skip_fn__split_part end if @ver>120919 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__split_part') with nowait goto skip_fn__split_part end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__split_part') with nowait if exists( select top 1 null from sys.objects where name='fn__split_part' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__split_part] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:120919\A.Sirna: bugfix v:110801\A.Sirna: return specified part of splitted string t: select dbo.fn__split_part(''25:32'','':'',1) */ CREATE function dbo.fn__split_part( @s nvarchar(4000), @separator nvarchar(50), @part int ) returns nvarchar(4000) as begin if @part < 0 goto ret declare @index int declare @spart nvarchar(4000) set @index = 0 while len(@s) > 0 begin if charindex(@separator,@s) = 0 begin if @index = @part begin set @spart = @s goto ret end set @spart = NULL goto ret end select @spart = substring(@s,0,charindex(@separator,@s)), @s = substring(@s,charindex(@separator,@s)+1,len(@s)) if @index = @part goto ret else set @index = @index+1 end ret: return @spart end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__split_part: -- ============================================================= fn__sql_def_col select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_def_col',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110324 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_def_col') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_def_col') with nowait goto skip_fn__sql_def_col end if @ver>110324 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_def_col') with nowait goto skip_fn__sql_def_col end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_def_col') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_def_col' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_def_col] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:110324\s.zaglio: adapted to mssql2k5 v:100919\s.zaglio: a bug near binary size v:100404\s.zaglio: collate before null/not null v:100328\s.zaglio: bug near default v:100110\s.zaglio: return tsql column declaration t:see [fn__sql_def_tbl] test */ CREATE function [dbo].[fn__sql_def_col]( @table sysname, @new sysname, @column sysname, @utype int, @type sysname, @len int, @prec int, @scale int, @nullable bit, @default sysname, @def_fx sysname, @identity bit, @computed bit, @function sysname, @chk sysname, @chk_fx sysname, @collation sysname, @status int, @filler bit ) returns nvarchar(4000) as begin -- select * from systypes where xtype in (175,239,231,167) -- select * from syscolumns c where c.type=108 id=object_id(''sp__printf'') -- declare @def nvarchar(4000) if @identity is null select @identity=case when @status & 0x80=0x80 then 1 else 0 end if @new is null select @new=@table select @def= -- name @column+'' ''+ -- type case when @computed=0 then @type + case -- select * from systypes when @utype in (175,239,231,167) --char,nchar,nvc,vc or @type in (''char'',''nchar'',''nvarchar'',''varchar'',''binary'',''varbinary'') then ''('' + case when @prec<0 then ''max'' else cast(@prec as nvarchar) end +'') '' -- (@len/case --when left(@column,1) =''n'' --then 2 else 1 end) as nvarchar) + '') '' when @utype in (106,108) or @type in (''decimal'',''numeric'') then ''('' + cast(@prec as nvarchar)+'',''+ cast(@scale as nvarchar)+'') '' else '''' end + -- collate isnull('' collate ''+ @collation,'''')+ -- nullable case when @nullable=1 and @identity!=1 then '' null '' else '' not null '' end + -- identity case when @identity = 1 then '' identity('' + cast(ident_seed(@table) as nvarchar)+'',''+ cast(ident_incr(@table) as nvarchar) + '') '' else '''' end + -- constrain isnull('' constraint ['' + @chk + ''_'' + @new+ ''] check '' + @chk_fx ,'''') + -- default isnull('' constraint '' + @default ,'''') + isnull('' default '' + @def_fx ,'''') + '''' -- computation else '' as '' + @function end return @def end -- fn__sql_def_col' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_def_col: -- ============================================================= fn__sql_def_typ select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_def_typ',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100321 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_def_typ') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_def_typ') with nowait goto skip_fn__sql_def_typ end if @ver>100321 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_def_typ') with nowait goto skip_fn__sql_def_typ end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_def_typ') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_def_typ' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_def_typ] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g: utility,script v: 100321\s.zaglio: return tsql type declaration t: see [fn__sql_def_col] test */ create function [dbo].[fn__sql_def_typ]( @utype int, @type sysname, @len int, @prec int, @scale int, @nullable bit ) returns nvarchar(4000) as begin -- select * from systypes where xtype in (175,239,231,167) -- select top 1 * from syscolumns /* select c.name,dbo.fn__sql_def_typ(c.xusertype,null,c.length,c.prec,c.scale,c.isnullable),c.* from syscolumns c where id=object_id(''sp__usage'') */ declare @def nvarchar(4000) select @def=case when @type is null then type_name(@utype) else @type end+ case -- select * from systypes when @utype in (175,239,231,167) --char,nchar,nvc,vc then ''('' + cast(@prec as nvarchar) +'') '' -- (@len/case --when left(@column,1) =''n'' --then 2 else 1 end) as nvarchar) + '') '' when @utype in (106,108) then ''('' + cast(@prec as nvarchar)+'',''+ cast(@scale as nvarchar)+'') '' else '''' end+ -- nullable case when @nullable=1 then '' null '' else '' not null '' end return @def end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_def_typ: -- ============================================================== fn__sql_format select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_format',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091022 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_format') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_format') with nowait goto skip_fn__sql_format end if @ver>091022 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_format') with nowait goto skip_fn__sql_format end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_format') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_format' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_format] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091022\s.zaglio: better view v:080815\S.Zaglio: reformat a string that containt sql code t: begin declare @s nvarchar(500) set @s=''select a, b, c, from ''+char(13)+char(10)+'' table'' set @s=dbo.fn__sql_format(@s,120) print @s end */ CREATE function [dbo].[fn__sql_format](@sql nvarchar(4000), @wrap smallint) returns nvarchar(4000) as begin declare @crlf nchar(2) select @crlf=char(13)+char(10) set @sql=replace(lower(@sql),@crlf,'' '') set @sql=replace(@sql,''update '', @crlf+''UPDATE '') set @sql=replace(@sql,''insert '', @crlf+''INSERT '') set @sql=replace(@sql,''select '', @crlf+''SELECT '') set @sql=replace(@sql,''set '', ''SET '') set @sql=replace(@sql,''right '', ''RIGHT '') set @sql=replace(@sql,''INNER '', ''INNER '') set @sql=replace(@sql,''outer '', ''OUTER '') set @sql=replace(@sql,''join '', ''JOIN '') set @sql=replace(@sql,''on '', ''ON '') set @sql=replace(@sql,''or '', ''OR '') set @sql=replace(@sql,''and '', ''AND '') set @sql=replace(@sql,''set '', ''SET '') set @sql=replace(@sql,''left '', ''LEFT '') set @sql=replace(@sql,''from '', @crlf+''FROM '') set @sql=replace(@sql,''into '', ''INTO '') set @sql=replace(@sql,''where '', @crlf+''WHERE '') set @sql=replace(@sql,''order by '', @crlf+''ORDER BY '') set @sql=replace(@sql,''group by '', ''GROUP BY '') return dbo.fn__str_split(dbo.fn__str_simplify(@sql,0),@wrap) end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_format: -- =========================================================== fn__sql_normalize select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_normalize',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120913 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_normalize') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_normalize') with nowait goto skip_fn__sql_normalize end if @ver>120913 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_normalize') with nowait goto skip_fn__sql_normalize end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_normalize') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_normalize' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_normalize] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:normalize, simplify v:120913\s.zaglio: a bug in exp semplification v:120903\s.zaglio: added exp option v:120820\s.zaglio: used () around top % v:120809\s.zaglio: remove extra from code and put on single line d:120809\s.zaglio: fn__sql_simplify t:print dbo.fn__sql_normalize('' test ''+char(13)+'' '',default) t:print dbo.fn__sql_normalize('' test -- comment''+char(13)+'' '',default) t:print dbo.fn__sql_normalize('' dt desc'',''ord'') t:select dbo.fn__sql_normalize('' 20%'',''top'') t:select dbo.fn__sql_normalize('' 20'',''top'') t: select dbo.fn__sql_normalize('' t1.f1="a", t2.f2=t3.f3 '', ''exp'') t: select dbo.fn__sql_normalize('' t1.f1="a" and t2.f2=t3.f3 '', ''exp'') */ CREATE function fn__sql_normalize ( @sql nvarchar(max), @opt sysname ) returns nvarchar(max) as begin declare @crlf nvarchar(2), @cr nvarchar(1), @lf nvarchar(1), @tab nvarchar(1), @sel bit, -- sel option specified @ord bit, -- ord option @top bit, @exp bit if @sql is null return null if charindex(''--'',@sql)>0 return null select @cr=cr,@lf=lf,@tab=tab,@crlf=crlf, @opt=case when not @opt is null then dbo.fn__str_quote(isnull(@opt,''''),''|'') else null end from dbo.fn__sym() while charindex(@cr,@sql)>0 select @sql=replace(@sql,@cr,'' '') while charindex(@lf,@sql)>0 select @sql=replace(@sql,@lf,'' '') while charindex(@tab,@sql)>0 select @sql=replace(@sql,@tab,'''') while charindex('' '',@sql)>0 select @sql=replace(@sql,'' '','' '') select @sql=ltrim(rtrim(@sql)) if @sql='''' return null if not @opt is null begin select @sel=charindex(''|sel|'',@opt), @ord=charindex(''|ord|'',@opt), @top=charindex(''|top|'',@opt), @exp=charindex(''|exp|'',@opt) if @sel=1 -- expand table name to select begin if left(@sql,7)!=''select '' select @sql=''select top 100 percent * from ''+dbo.fn__str_quote(@sql,''[]'') end if @ord=1 -- expand to oby expression begin if left(@sql,9)!=''order by '' select @sql=''order by ''+@sql end if @top=1 -- convert n or n% to top ... begin if (right(@sql,1)=''%'' and isnumeric(left(@sql,len(@sql)-1))=0) or (right(@sql,1)!=''%'' and isnumeric(@sql)=0) select @sql=''#wrong number or percent'' else begin if right(@sql,1)=''%'' select @sql=''top (''+cast(left(@sql,len(@sql)-1) as sysname) +'') percent'' else select @sql=''top (''+cast(left(@sql,len(@sql)) as sysname)+'')'' end end -- top if @exp=1 -- expression for join: replace " with '''' and strip spaces begin select @sql=replace(@sql,''"'','''''''') -- todo: for {sym}{spc} and {spc}{sym} end end -- options return @sql end -- fn__sql_normalize' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_normalize: -- =========================================================== fn__sql_quotename select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_quotename',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080505 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_quotename') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_quotename') with nowait goto skip_fn__sql_quotename end if @ver>080505 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_quotename') with nowait goto skip_fn__sql_quotename end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_quotename') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_quotename' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_quotename] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080505\S.Zaglio: add bounds [ & ] if not exists */ create function fn__sql_quotename( @name sysname ) returns sysname as begin if left(@name,1)<>''['' and right(@name,1)<>'']'' set @name=quotename(@name) return @name end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_quotename: -- =============================================================== fn__sql_strip select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_strip',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100228 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_strip') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_strip') with nowait goto skip_fn__sql_strip end if @ver>100228 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_strip') with nowait goto skip_fn__sql_strip end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_strip') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_strip' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_strip] begin try exec dbo.sp_executesql @statement = N'/* l:see LICENSE file g:utility v:100228\s.zaglio: added strip of space and condition on comment v:091018\s.zaglio: remove comments from @sql t: declare @sql nvarchar(4000) select @sql='''' create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script ''fn__sql_strip'',@out=''#src'' select @sql=@sql+line+char(13)+char(10) from #src order by lno print @sql print ''------------------------------------------------------'' print dbo.fn__sql_strip(@sql,0) print ''------------------------------------------------------'' print dbo.fn__sql_strip(@sql,1) drop table #src t:sp__find ''fn__sql_strip'' */ CREATE function [dbo].[fn__sql_strip]( @sql nvarchar(4000), @comments bit=null ) returns nvarchar(4000) as begin declare @crlf nchar(2),@cr nchar(1),@lf nchar(1),@tab nchar(1) select @crlf=crlf,@cr=cr,@lf=lf,@tab=tab from dbo.fn__sym() select @sql=replace(@sql,@cr,'' '') select @sql=replace(@sql,@lf,'' '') -- newline select @sql=replace(@sql,@tab,'' '') -- tab select @sql=ltrim(rtrim(@sql)) while (charindex('' '',@sql)>0) select @sql=replace(@sql,'' '','' '') if not @comments is null begin -- this bit strips out block comments. we need to strip them out before -- single line comments (like this one), because you could theoretically have -- a block comment like this: /* my comment -- is malformed */ -- variables to hold the first and last character''s positions in the "next" block -- comment in the string declare @codeblockstart int, @codeblockend int set @codeblockstart = patindex(''%/*%'', @sql) -- loop as long as we still have comments to exorcise ;) while @codeblockstart > 0 begin -- grab the last character in the code block by searching for the first incidence -- of */ (close comment) in the string. set @codeblockend = patindex(''%*/%'', @sql) -- "cut" out the comment by concatenating everything the the "left" and "right" -- of the comment set @sql = left(@sql, @codeblockstart - 1) + right(@sql, len(@sql) - (@codeblockend + 1)) -- fetch the first character''s position in the next comment block, if there is one. set @codeblockstart = patindex(''%/*%'', @sql) end -- once code blocks are out, we can remove any lines commented by double dashes (like this one) -- variables to hold the first and last character''s position in the "next" code block. declare @doubledashstart int, @doubledashlineend int -- grab the first double-dash (if there is one) set @doubledashstart = patindex(''%--%'', @sql) while @doubledashstart > 0 begin -- search for the first "new line" after the first "double dash" -- we can use nchar(13) and nchar(10) to find the new line. -- since patindex doesn''t have a "start" character, and we need to find -- the first new line after the double dash, we will search all characters -- after the double dash for the new line. set @doubledashlineend = patindex(''%'' + nchar(13) + nchar(10) + ''%'', right(@sql, len(@sql) - (@doubledashstart))) + @doubledashstart -- "cut" out the comment, as was done with the block comments. set @sql = left(@sql, @doubledashstart - 1) + right(@sql, len(@sql) - @doubledashlineend) -- check for the next incidence of a double dash, if there is one. set @doubledashstart = patindex(''%--%'', @sql) end -- return the uncommented string end -- comments return @sql end -- fn__sql_strip' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_strip: -- ================================================================ fn__sql_trim select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_trim',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120412 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_trim') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_trim') with nowait goto skip_fn__sql_trim end if @ver>120412 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_trim') with nowait goto skip_fn__sql_trim end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_trim') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_trim' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_trim] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120412\s.zaglio: left and right trim lines to allow correct indent into code t: print dbo.fn__sql_trim('' /* test v:120412\s.zaglio:test */ create proc -- test 2 right spaces '') */ CREATE function fn__sql_trim(@sql nvarchar(max)) returns nvarchar(max) as begin declare @tmp nvarchar(max),@crlf nvarchar(2),@i int,@j int,@p int declare @src table(lno int identity primary key,line nvarchar(4000)) select @crlf=crlf from fn__sym() insert @src(line) select token from dbo.fn__str_table(@sql,@crlf) select top 1 @i=lno from @src where ltrim(rtrim(line))!='''' order by lno select top 1 @j=lno from @src where ltrim(rtrim(line))!='''' order by lno desc select @p=patindex(''%[^ ]%'',line) from @src where lno=@i select @tmp='''' select @tmp=@tmp+rtrim(substring(line,@p,4000))+@crlf from @src where lno between @i and @j return @tmp end -- fn__sql_trim' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_trim: -- ========================================================= fn__sql_unquotename select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__sql_unquotename',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090914 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__sql_unquotename') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__sql_unquotename') with nowait goto skip_fn__sql_unquotename end if @ver>090914 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__sql_unquotename') with nowait goto skip_fn__sql_unquotename end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_unquotename') with nowait if exists( select top 1 null from sys.objects where name='fn__sql_unquotename' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__sql_unquotename] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090914\s.zaglio: revisited using parsename to manage composed names v:080505\S.Zaglio: remove bounds [ & ] if exists t:print dbo.fn__sql_unquotename(''[dbo].[test]'') t:print dbo.fn__sql_unquotename(''[test]'') */ CREATE function [dbo].[fn__sql_unquotename]( @name sysname ) returns sysname as begin select @name=coalesce(parsename(@name,4)+''.'','''')+coalesce(parsename(@name,3)+''.'','''')+coalesce(parsename(@name,2)+''.'','''')+parsename(@name,1) -- if left(@name,1)=''['' and right(@name,1)='']'' set @name=substring(@name,2,len(@name)-2) return @name end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__sql_unquotename: -- ================================================================== fn__str_at select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_at',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131010 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_at') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_at') with nowait goto skip_fn__str_at end if @ver>131010 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_at') with nowait goto skip_fn__str_at end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_at') with nowait if exists( select top 1 null from sys.objects where name='fn__str_at' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_at] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,util_tkns v:131010\s.zaglio: a try of optimization v:111114\s.zaglio: simplyfied and added to grp util_tkns v:100919\s.zaglio: added management of sep '' '' v:091018\s.zaglio: replaced datalengh with len for problem with unicode v:090805\S.Zaglio: now on @pos=0 return null v:081212\S.Zaglio: now support @sep='' '' v:081204\S.Zaglio: removed bug limits 128 chars v:081130\S.Zaglio: replaced fn_str_at and optimized v:081110\S.Zaglio: expanded @seps to nvarchar(32) v:080909\S.Zaglio: added outbounds tests and -n as from right and return of varchar4000 nad null case v:080717\S.Zaglio: normalize position for fn_str_at t: -- due wide use of this, a good test is needed declare @tbl table(id int, s sysname,sep sysname,p int,v sql_Variant,r sql_variant) insert @tbl(id,s,sep,p,r) select 10,''a'',''|'',4,null insert @tbl(id,s,sep,p,r) select 20,''a|b'',''|'',-1,null insert @tbl(id,s,sep,p,r) select 22,''a|b'',''|'',-2,null insert @tbl(id,s,sep,p,r) select 24,''a|b'',''|'',-3,null insert @tbl(id,s,sep,p,r) select 30,'''',''|'',1,'''' insert @tbl(id,s,sep,p,r) select 40,''a|b|c'',''|'',1,''a'' insert @tbl(id,s,sep,p,r) select 50,''|b|c'',''|'',1,'''' insert @tbl(id,s,sep,p,r) select 60,''a|b|c'',''|'',2,''b'' insert @tbl(id,s,sep,p,r) select 70,''a|b|c'',''|'',3,''c'' insert @tbl(id,s,sep,p,r) select 93,''a|b|c'',''|'',0,null insert @tbl(id,s,sep,p,r) select 96,''a b c'','''',3,''c'' insert @tbl(id,s,sep,p,r) select 100,''abc de fg'','''',1,''abc'' insert @tbl(id,s,sep,p,r) select 110,''abc de fg'','''',2,''de'' insert @tbl(id,s,sep,p,r) select 120,''abc de fg'','''',3,''fg'' insert @tbl(id,s,sep,p,r) select 130,''abc de fg'','''',4,null insert @tbl(id,s,sep,p,r) select 140,''abc de fg '','' '',2,'' de fg'' insert @tbl(id,s,sep,p,r) select 140,''abc de fg '','''',3,'''' insert @tbl(id,s,sep,p,r) select 150,'' abc de fg '','''',3,'''' insert @tbl(id,s,sep,p,r) select 160,'' abc de fg '',''abc'',4,null update @tbl set v=dbo.fn__str_at(s,sep,p) select *,case when v=r or v is null and r is null then ''ok'' else ''ko'' end rr from @tbl */ CREATE function [dbo].[fn__str_at]( @data nvarchar(4000), @sep nvarchar(32), @pos int ) returns nvarchar(4000) as begin declare @st nvarchar(4000) declare @i int,@j int declare @step int if @data is null or @sep is null return null --initialize select @st = '''' select @step = len(''.''+@sep+''.'')-2 if @sep = '''' and @step=0 select @sep = '' '',@step=1 select @data = @data + @sep , @j=1 select @i = charindex(@sep, @data) /* this do not optimize nothing: - if @pos=1 return left(@data,@i-1) (same time) - use of fn__str_split or fn__str_parse that uses with (5-8 time slower) */ while (@i <> 0) begin select @pos=@pos-1 if @pos=0 return substring(@data, @j, @i - @j) set @j=@i+@step set @i = charindex(@sep, @data,@j) end return null end -- fn__str_at' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_at: -- ============================================================= fn__str_between select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_between',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130217 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_between') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_between') with nowait goto skip_fn__str_between end if @ver>130217 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_between') with nowait goto skip_fn__str_between end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_between') with nowait if exists( select top 1 null from sys.objects where name='fn__str_between' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_between] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130217\s.zaglio: added option close left v:111205\s.zaglio: a test when left token not found v:111114\s.zaglio: added space as separator and correct some bug v:110707\s.zaglio: a bug when @str = '''' v:100508\s.zaglio: return a pieec of string between limits t:print dbo.fn__str_between(''a:1,b:2,c:3'',''a:'','','',default) -->1 t:print dbo.fn__str_between(''a:1,b:2,c:3'',''b:'','','',default) -->2 t:print dbo.fn__str_between(''a:1,b:2,c:3'',''c:'','','',default) -->3 t:print ''|''+dbo.fn__str_between(''a:1,b:2,c:3'',''x'',''y'',default)+''|'' -->''||'' t:print isnull(dbo.fn__str_between(null,''c:'','','',default),''???'') -->??? t:print ''|''+isnull(dbo.fn__str_between('''',''c:'','','',default),''???'')+''|'' -->''||'' t:print dbo.fn__str_between(''test:with space'','':'','''',default) -->with t:print ''|''+dbo.fn__str_between(''||'',''|ss:'',''|'',default)+''|'' -->''||'' t:print dbo.fn__str_between(''|ss:m0|'',''|ss:'',''|'',default) --> m0 t:select dbo.fn__str_between(''c:\dir\file.ext'',''\'',''.'',[btw.close_right]) from enums */ CREATE function fn__str_between( @str nvarchar(4000), @from sysname, @to sysname, @opt smallint=null ) returns nvarchar(4000) as begin declare @x1 int,@x2 int,@l int,@cr smallint,@lto int,@lfrom int if @str is null or @from is null or @to is null return null if @str='''' return @str -- spaces tric select @lto=len(''"''+@to+''"'')-2,@lfrom=len(''"''+@from+''"'')-2 if @opt is null begin select @x1=case when @from='''' then charindex('' '',@str) else charindex(@from,@str) end if @x1=0 return '''' select @x1=@x1+@lfrom, @x2=case when @to='''' then charindex('' '',@str,@x1) else charindex(@to,@str,@x1) end end else begin select @cr=[btw.close_right] from enums if @opt=@cr begin select @x2=case when @to='''' then dbo.fn__charindex('' '',@str,-1) else dbo.fn__charindex(@to,@str,-1) end if @x2=0 return '''' select /*@x2=@x2-@lto,@x1=@x2*/ @x1=@x2-@lto while @x1>0 and substring(@str,@x1,@lfrom)!=@from select @x1=@x1-1 if @x1>0 select @x1=@x1+@lfrom end end -- not default close_left if @x1=@x2 return '''' select @l=len(@str) if @x2=0 select @x2=@l+1 return substring(@str,@x1,@x2-@x1) end -- fn__str_between' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_between: -- ================================================================= fn__str_chk select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_chk',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121004 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_chk') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_chk') with nowait goto skip_fn__str_chk end if @ver>121004 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_chk') with nowait goto skip_fn__str_chk end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_chk') with nowait if exists( select top 1 null from sys.objects where name='fn__str_chk' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_chk] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:121004\s.zaglio: renamed into fn__str_chk d:121004\s.zaglio: fn__chk_str v:110219\s.zaglio: check if a string contain only specified chars t:print dbo.fn__chk_str(''correct_me@email.it'',''a-z|0-9|_.@;'') -- ok t:print dbo.fn__chk_str(''correct_me@email.it,me@svr'',''a-z|0-9|_.;'') -- bad */ create function fn__str_chk(@str nvarchar(4000),@chars nvarchar(4000)) returns bit as begin /* declare @str nvarchar(4000),@chars nvarchar(4000) select @str=''k@;k'',@chars=''a-z|@_'' -- print dbo.fn__str_quote(''a|b'',''|'') */ declare @tkn sysname,@c nchar(1),@i int,@l int,@ok bit select @chars=dbo.fn__str_unquote(@chars,''|''), @l=len(@str),@i=1 declare cs cursor local for select ''[''+token+'']'' from dbo.fn__str_table(@chars,''|'') while (@i<=@l) begin select @ok=0,@c=substring(@str,@i,1) open cs while 1=1 begin fetch next from cs into @tkn if @@fetch_status!=0 break if @c like @tkn select @ok=1 -- exec sp__printf ''c(%s) tkn(%s) ok(%d)'',@c,@tkn,@ok end close cs if @ok=0 return 0 select @i=@i+1 end deallocate cs return 1 end -- fn__chk_str' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_chk: -- =============================================================== fn__str_count select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_count',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_count') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_count') with nowait goto skip_fn__str_count end if @ver>100919 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_count') with nowait goto skip_fn__str_count end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_count') with nowait if exists( select top 1 null from sys.objects where name='fn__str_count' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_count] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919\s.zaglio: added sep '''' for '' '' v:100228\s.zaglio: optimized with use of charindex v:091018\s.zaglio: replaced datalenght(@sep) with len coz unicode problem v:081212\S.Zaglio: replaced len(@sep) with datalenght v:081130\S.Zaglio: optimization & corrected a bug v:081110\S.Zaglio: expanded @seps to nvarchar(32) v:080926\S.Zaglio: added null & '''' cases v:080721\S.Zaglio: count tokens t:print dbo.fn__str_count(''a|b|c'',''|'') --> 3 t:print dbo.fn__str_count(''a|b|'',''|'') --> 3 (ex 2) t:print dbo.fn__str_count(''a'',''|'') --> 1 t:print dbo.fn__str_count('''',''|'') --> 0 t:print dbo.fn__str_count(null,''|'') --> null t:print dbo.fn__str_count(''a b c d'','''') */ CREATE function [dbo].[fn__str_count](@tokens nvarchar(4000),@sep nvarchar(32)=''|'') returns int as begin declare @i int set @i=0 declare @n int set @n=0 if @tokens is null return null if @tokens='''' return 0 if @sep='''' select @tokens=replace(@tokens,'' '',''|''),@sep=''|'' declare @k int set @k=len(@sep) declare @l int set @l=len(@tokens) select @i=charindex(@sep,@tokens) while @i>0 begin select @n=@n+1 select @i=charindex(@sep,@tokens,@i+@k) end -- while /* old: while @i<=@l begin if substring(@tokens,@i,@k)=@sep set @n=@n+1 set @i=@i+1 end -- while */ return @n+1 end -- fn__str_count' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_count: -- ================================================================= fn__str_cut select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_cut',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090910.1827 begin if @aut!='G.Sorgente' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_cut') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_cut') with nowait goto skip_fn__str_cut end if @ver>090910.1827 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_cut') with nowait goto skip_fn__str_cut end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_cut') with nowait if exists( select top 1 null from sys.objects where name='fn__str_cut' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_cut] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:090910.1827\G.Sorgente: remove nchar from begin or end of the string --t: print dbo.fn__str_cut (''0002'',''0'',1) --t: print dbo.fn__str_cut (''2000'',''0'',1) --t: print dbo.fn__str_cut (''2000'',''0'',0) --t: print dbo.fn__str_cut (''2002'',''0'',1) --t: print dbo.fn__str_cut (''2002'',''0'',0) --t: print dbo.fn__str_cut ('' 2 '',space(1),1)+''|'' --t: print dbo.fn__str_cut ('' 2 '',space(1),0)+''|'' */ CREATE function [dbo].[fn__str_cut] ( @str nvarchar(4000) ,@c nvarchar(2) ,@left bit ) returns nvarchar(4000) as begin if @c='''' or @c=space(1) set @c=N''Þ'' set @str = replace(@str,'' '',N''Þ'') if @left is null set @left=1 declare @ch nchar(2) set @ch='''' declare @i int if (@left=1) set @i=1 else set @i=len(@str) while (1=1) begin set @ch=substring(@str,@i,1) if coalesce(@ch,'''')='''' goto ex if (@ch!=@c) goto ex if (@left=1) begin if (@i>=len(@str)) goto ex set @str=substring(@str,@i+1,len(@str)) --set @i=@i+1 end else begin if (@i<=1) goto ex set @str=substring(@str,1,@i-1) set @i=@i-1 end -- (end -if) end -- (end - while) ex: set @str = replace(@str,N''Þ'','' '') return @str end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_cut: -- ================================================================= fn__str_exp select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_exp',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091227 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_exp') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_exp') with nowait goto skip_fn__str_exp end if @ver>091227 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_exp') with nowait goto skip_fn__str_exp end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_exp') with nowait if exists( select top 1 null from sys.objects where name='fn__str_exp' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_exp] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091227\s.zaglio: added %idx% (not for multi) v:081110\S.Zaglio: expanded @seps to nvarchar(32) v:081011\S.Zaglio: added @@ marker for multiple replace v:080814\S.Zaglio: generalized separator v:080729\S.Zaglio: repeat expression with %% replacing it with tokens or repleace multiple @@ t:print dbo.fn__str_exp(''dst.%%=src.%%'',''a|b|c'','', '') --> dst.a=src.a,dst.b=src.b,... t:print dbo.fn__str_exp(''dst.@@ and src.@@'',''a|b|c'',''|'') --> dst.a and src.b || MULTI t:print dbo.fn__str_exp(''%%=''''@@'''''',''a,b,c'','','') --> a=''@@'',b=''@@'',c=''@@'' t:print dbo.fn__str_exp(''''''%%'''' [%idx%]'',''a,b,c'','','') --> ''a'' [1],''b'' [2],''c'' [3] */ CREATE function [dbo].[fn__str_exp]( @expression nvarchar(4000), @tokens nvarchar(4000), @sep nvarchar(32) ) returns nvarchar(4000) as begin declare @r nvarchar(4000) select @r='''' declare @n int,@i int,@k int,@l int declare @multi bit select @multi=0 declare @stri sysname,@ri bit if @sep is null return null set @n=dbo.fn__str_count(@tokens,''%%'') --return dbo.fn__printf(''%d'',@n,null,null,null,null,null,null,null,null,null) select @ri=case when charindex(''%idx%'',@expression)>0 then 1 else 0 end set @k=charindex(''%%'',@expression) if @k=0 begin set @k=charindex(''@@'',@expression) if @k>0 begin set @multi=1 set @l=len(@expression) end else set @k=1 end set @n=dbo.fn__str_count(@tokens,dbo.fn__trim(@sep)) set @i=1 while (@i<=@n and @k>0) begin if @multi=0 begin if @ri=1 begin select @stri=convert(sysname,@i) set @r=@r+replace(replace(@expression,''%idx%'',@stri),''%%'', dbo.fn__str_at(@tokens,dbo.fn__trim(@sep),@i)) end else set @r=@r+replace(@expression,''%%'',dbo.fn__str_at(@tokens,dbo.fn__trim(@sep),@i)) end else begin set @expression=substring(@expression,1,@k-1)+ dbo.fn__str_at(@tokens,dbo.fn__trim(@sep),@i)+substring(@expression,@k+2,@l) set @k=charindex(''@@'',@expression,1) end if @i<@n select @r=@r+@sep set @i=@i+1 end -- while if @multi=0 return @r return @expression end -- fn__str_exp' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_exp: -- ================================================================ fn__str_flow select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_flow',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120810.1200 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_flow') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_flow') with nowait goto skip_fn__str_flow end if @ver>120810.1200 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_flow') with nowait goto skip_fn__str_flow end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_flow') with nowait if exists( select top 1 null from sys.objects where name='fn__str_flow' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_flow] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:text,layout,grid v:120810.1200\s.zaglio: flow a horiz. list of items into a grid t: print dbo.fn__str_flow(''abcdefghi,abcdefghi,abcdefghi,abcdefghi,''+ ''abcdefghi,abcdefghi,abcdefghi,abcdefghi'', '','', default) */ CREATE function fn__str_flow( @list nvarchar(4000), @sep nvarchar(32), @opt sysname = null ) returns nvarchar(4000) as begin declare @n int,@ret nvarchar(4000),@width smallint,@ll int, @crlf nvarchar(2) select @width=80, @sep=isnull(@sep,''|''), @crlf=crlf from fn__sym() if not @opt is null begin select @opt=dbo.fn__str_quote(@opt,''|'') if charindex(''|132|'',@opt)>0 select @width=132 end select @n=max(len(token))+1 from dbo.fn__str_table(@list,@sep) select @ll=(@width/@n*@n)+2 -- select * from dbo.fn__str_table(''a,b,c'','','') select @ret =coalesce(@ret+@sep,'''')+left(token+replicate('' '',@n),@n) +case when (pos+1)%(@width/(@n+1))=0 then @crlf else '' '' end from dbo.fn__str_table(@list,@sep) return @ret end -- proc fn__str_flow' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_flow: -- ================================================================ fn__str_guid select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_guid',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100511 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_guid') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_guid') with nowait goto skip_fn__str_guid end if @ver>100511 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_guid') with nowait goto skip_fn__str_guid end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_guid') with nowait if exists( select top 1 null from sys.objects where name='fn__str_guid' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_guid] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100511\s.zaglio: normalize a guid to become a table name t:print ''##''+dbo.fn__str_guid(newid()) */ create function fn__str_guid(@gid uniqueidentifier) returns sysname as begin declare @s sysname select @s=replace(convert(sysname,@gid),''-'','''') return @s end -- fn__str_guid' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_guid: -- ================================================================== fn__str_in select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_in',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100306 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_in') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_in') with nowait goto skip_fn__str_in end if @ver>100306 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_in') with nowait goto skip_fn__str_in end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_in') with nowait if exists( select top 1 null from sys.objects where name='fn__str_in' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_in] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100306\s.zaglio: added match char by char if @sep='''' v:090610\S.Zaglio: match a seached list with a gived list t:print dbo.fn__str_in(''a,d'',''a,b,c,d'','','') --> 1 t:print dbo.fn__str_in(''a,e'',''a,b,c,d'','','') --> 0 t:print dbo.fn__str_in(null,''a,b,c,d'','','') --> null t:print dbo.fn__str_in(''ab'',''abcd'','''') --> 1 t:print dbo.fn__str_in(''ae'',''abcd'','''') --> 0 */ CREATE function fn__str_in( @searched nvarchar(4000), @tokens nvarchar(4000),@sep nvarchar(32)=''|'' ) returns bit as begin declare @i int,@n int,@r bit if @sep='''' begin select @n=len(@searched),@i=1 while (@i<=@n) begin if charindex(substring(@searched,@i,1),@tokens)=0 return 0 select @i=@i+1 end select @r=1 end else begin select @n=count(*) from dbo.fn__str_table(@searched,@sep) select @i=count(*) from dbo.fn__str_table(@tokens,@sep) t inner join dbo.fn__str_table(@searched,@sep) s on t.token=s.token if @i=@n select @r=1 else select @r=0 end return @r end -- fn__str_in' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_in: -- ================================================================ fn__str_jaro select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_jaro',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100125 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_jaro') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_jaro') with nowait goto skip_fn__str_jaro end if @ver>100125 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_jaro') with nowait goto skip_fn__str_jaro end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_jaro') with nowait if exists( select top 1 null from sys.objects where name='fn__str_jaro' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_jaro] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:100125\s.zaglio: alternative to fn__str_distance based on jaro algho c:originally from http://www.sqlservercentral.com/articles/Fuzzy+Match/65702/ t:print dbo.fn__str_jaro(''Peter'',''Pete'') -- 0.933332 t:print dbo.fn__str_jaro(''Peter'',''Peter'') */ CREATE function [dbo].[fn__str_jaro](@str1 varchar(4000), @str2 varchar(4000)) returns float as begin declare @jaro_distance float declare @jaro_winkler_distance float declare @prefixlength int declare @prefixscalefactor float -- used by calc of prefixlength declare @i int declare @n int declare @foundit bit -- used by calc of jaro declare @common1 varchar(4000) declare @common2 varchar(4000) declare @common1_len int declare @common2_len int declare @s1_len int declare @s2_len int declare @match_window int set @jaro_distance = 0 -- used by calc transposition declare @transpose_cnt int set @transpose_cnt = 0 set @prefixscalefactor = 0.1 --constant = .1 if @str1 is not null and @str2 is not null begin -- set @jaro_distance = dbo.fn__str_jaro_calc(@str1, @str2) set @match_window = 0 set @s1_len = len(@str1) set @s2_len = len(@str2) -- set @match_window = dbo.fn__str_jaro_clmw(@s1_len, @s2_len) -- calclatematchwindow set @match_window = case when @s1_len >= @s2_len then (@s1_len / 2) - 1 else (@s2_len / 2) - 1 end -- case set @common1 = dbo.fn__str_jaro_gcc(@str1, @str2, @match_window,@s1_len,@s2_len) -- getcommoncharacters set @common1_len = len(@common1) if @common1_len = 0 or @common1 is null goto exit_dist set @common2 = dbo.fn__str_jaro_gcc(@str2, @str1, @match_window,@s1_len,@s2_len) set @common2_len = len(@common2) if @common1_len <> @common2_len or @common2 is null goto exit_dist -- begin calc transposition -- set @transpose_cnt = dbo.fn__str_jaro_ctp](@common1_len, @common1, @common2) -- calctranspositions set @i = 0 while @i < @s1_len begin if substring(@str1, @i+1, 1) <> substring(@str2, @i+1, 1) set @transpose_cnt = @transpose_cnt + 1 set @i = @i + 1 end -- while set @transpose_cnt = @transpose_cnt / 2 -- end calc transposition set @jaro_distance = @common1_len / (3.0 * @s1_len) + @common1_len / (3.0 * @s2_len) + (@common1_len - @transpose_cnt) / (3.0 * @common1_len); exit_dist: -- set @prefixlength = dbo.fn__str_jaro_calc_pl(@str1, @str2) set @i = 0 set @foundit = 0 set @n = case when @prefixlength < @s1_len and @prefixlength < @s2_len then @prefixlength when @s1_len < @s2_len and @s1_len < @prefixlength then @s1_len else @s2_len end -- case while @i < @n and @foundit = 0 begin if substring(@str1, @i+1, 1) <> substring(@str2, @i+1, 1) begin set @prefixlength = @i set @foundit = 1 end set @i = @i + 1 end -- while end -- if not str nulls else set @prefixlength = 4 set @jaro_winkler_distance = @jaro_distance + ((@prefixlength * @prefixscalefactor) * (1.0 - @jaro_distance)) return @jaro_winkler_distance end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_jaro: -- ============================================================ fn__str_jaro_gcc select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_jaro_gcc',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100125 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_jaro_gcc') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_jaro_gcc') with nowait goto skip_fn__str_jaro_gcc end if @ver>100125 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_jaro_gcc') with nowait goto skip_fn__str_jaro_gcc end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_jaro_gcc') with nowait if exists( select top 1 null from sys.objects where name='fn__str_jaro_gcc' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_jaro_gcc] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100125\s.zaglio: used by fn__str_jaro_gcc c:originally from www.sqlservercentral.com t:print dbo.fn__str_jaro(''Peter'',''Pete'') */ create function [dbo].fn__str_jaro_gcc( @str1 varchar(4000), @str2 varchar(4000), @match_window int, @s1_len int, @s2_len int ) returns varchar(4000) as begin declare @commonchars varchar(4000) declare @copy varchar(4000) declare @char char(1) declare @foundit bit declare @i int declare @j int declare @j_max int set @commonchars = '''' set @copy = @str2 set @i = 1 while @i < (@s1_len + 1) begin set @char = substring(@str1, @i, 1) set @foundit = 0 -- set j starting value if @i - @match_window > 1 set @j = @i - @match_window else set @j = 1 -- set j stopping value if @i + @match_window <= @s2_len set @j_max = @i + @match_window else if @s2_len < @i + @match_window set @j_max = @s2_len while @j < (@j_max + 1) and @foundit = 0 begin if substring(@copy, @j, 1) = @char begin set @foundit = 1 set @commonchars = @commonchars + @char set @copy = stuff(@copy, @j, 1, ''#'') end set @j = @j + 1 end -- while @j<... set @i = @i + 1 end -- while @i<... return @commonchars end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_jaro_gcc: -- ================================================================ fn__str_mask select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_mask',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091127 begin if @aut!='g.sorgente' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_mask') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_mask') with nowait goto skip_fn__str_mask end if @ver>091127 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_mask') with nowait goto skip_fn__str_mask end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_mask') with nowait if exists( select top 1 null from sys.objects where name='fn__str_mask' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_mask] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:091127\g.sorgente: mask some description t: select ''[''+dbo.fn__str_mask(''pippo'',''*'',1,4)+'']'' select ''[''+dbo.fn__str_mask(''pipp'',''*'',1,2)+'']'' select ''[''+dbo.fn__str_mask(''abracadabra'',''*'',2,null)+'']'' */ CREATE function [dbo].[fn__str_mask] ( @v nvarchar(4000) ,@m nvarchar(2)=''*'' -- mask char ,@s tinyint=0 -- (0=stuff in middle,1=left stuff,2=right_stuff) ,@n tinyint=0 -- (set static len stuff, set it to null to automatic calculate it) ) returns nvarchar(4000) as begin declare @r nvarchar(4000), @max int, @i int set @max = coalesce(@n,convert(int,convert(float,len(@v))/2)) set @m = coalesce(@m,''*'') set @s = coalesce(@s,0) set @v = ltrim(rtrim(@v)) set @i = (len(@v)-@max)/2 if coalesce(@v,'''')='''' begin set @r=@v goto ret end if @i<=0 and @s=0 begin set @r=stuff(@v,1,len(@v),replicate(@m,len(@v))) goto ret end else begin select @r=case @s when 0 then stuff(@v,@i+1,@max,replicate(@m,@max)) when 1 then stuff(@v,1,@max,replicate(@m,@max)) when 2 then stuff(@v,(len(@v)-@max)+1,@max,replicate(@m,@max)) end end ret: return @r end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_mask: -- ================================================================= fn__str_mix select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_mix',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090210 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_mix') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_mix') with nowait goto skip_fn__str_mix end if @ver>090210 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_mix') with nowait goto skip_fn__str_mix end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_mix') with nowait if exists( select top 1 null from sys.objects where name='fn__str_mix' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_mix] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090210\S.Zaglio: optimized v:080811\S.Zaglio: managed nulls v:080101\S.Zaglio: update on change of fn__at v:080730\S.Zaglio: mix words of two groups separated by pipe withour repeatitions t:print dbo.fn__str_mix(''a|b|c'',''a|c|d'',''|'') -->''a|b|c|d'' t:print dbo.fn__str_mix(''d|b|c|a'',''a|c|b'',''|'') -->''d|b|c|a'' t:print dbo.fn__str_mix('''',''a|c|d'',''|'') -->''a|b|d'' t:print dbo.fn__str_mix(''a|b|c'','''',''|'') -->''a|b|c'' c:very slow. Must be optimized */ CREATE function fn__str_mix(@grp1 nvarchar(4000), @grp2 nvarchar(4000),@sep nvarchar(32)=''|'') returns nvarchar(4000) as begin declare @r nvarchar(4000) set @r='''' declare @t table(pos int identity(1,1), token nvarchar(4000)) if @grp1!='''' and @grp2!='''' insert into @t select token from dbo.fn__str_table(@grp2,@sep) union select token from dbo.fn__str_table(@grp1,@sep) else begin if @grp1='''' return @grp2 else return @grp1 end declare @n int,@i int select @n=count(*) from @t set @i=2 select @r=token from @t where pos=1 while (@i<=@n) begin select @r=@r+@sep+token from @t where pos=@i set @i=@i+1 end return @r /* declare @n int declare @m int declare @i int declare @token sysname if @grp1 is null return @grp2 if @grp2 is null return @grp1 set @n=dbo.fn__str_count(@grp2,@sep) set @m=dbo.fn__str_count(@grp2,@sep) set @i=1 if @n>@m while (@i<=@n) begin set @token=dbo.fn__str_at(@grp1,@sep,@i) if dbo.fn__at(@token,@grp2,@sep)=0 begin if @grp2<>'''' set @grp2=@grp2+@sep set @grp2=@grp2+@token end -- if set @i=@i+1 end -- while else while (@i<=@m) begin set @token=dbo.fn__str_at(@grp2,@sep,@i) if dbo.fn__at(@token,@grp1,@sep)=0 begin if @grp1<>'''' set @grp1=@grp1+@sep set @grp1=@grp1+@token end -- if set @i=@i+1 end -- while if @n>@m return @grp2 return @grp1 */ end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_mix: -- ================================================================= fn__str_pad select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_pad',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130523 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_pad') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_pad') with nowait goto skip_fn__str_pad end if @ver>130523 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_pad') with nowait goto skip_fn__str_pad end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_pad') with nowait if exists( select top 1 null from sys.objects where name='fn__str_pad' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_pad] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130523\s.zaglio: changed tag d of fn__pad to o v:091126\s.zaglio: renamed from fn__pad v:091027\s.zaglio: added @sep v:090611\s.Zaglio: align ntext and pad it o:130523\s.zaglio: fn__pad t:print dbo.fn__str_pad(''test'',10,null,null,null)+''|---'' t:print dbo.fn__str_pad(1234,10,null,null,null)+''|---'' */ CREATE function fn__str_pad( @src sql_variant, @width int, @sep nchar(1), @align tinyint, @decimals int ) returns nvarchar(4000) as begin declare @s nvarchar(4000) declare @n real, @num bit select @s=convert(nvarchar(4000),@src,126) if @align is null or @align=0 if isnumeric(@s)=1 select @align=1,@sep=coalesce(@sep,''0'') else select @align=0,@sep=coalesce(@sep,'' '') if @sep is null select @sep='' '' if @align=0 select @s=left(@s+replicate(@sep,@width),@width) if @align=1 select @s=right(replicate(@sep,@width)+@s,@width) -- todo: align=1 rigth -- todo: align=2 center -- todo: decimal management return @s end -- fn__str_pad' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_pad: -- =============================================================== fn__str_print select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_print',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100724 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_print') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_print') with nowait goto skip_fn__str_print end if @ver>100724 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_print') with nowait goto skip_fn__str_print end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_print') with nowait if exists( select top 1 null from sys.objects where name='fn__str_print' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_print] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100724\s.zaglio: added = and '' v:100228\s.zaglio: remove non ascii chars t:print dbo.fn__str_print(''abc:.d{f|5}6~4&-ò§sd='''''') */ CREATE function [dbo].[fn__str_print] (@s nvarchar(4000)) returns nvarchar(4000) as begin /* declare @i int select @i=32 while @i<128 begin print convert(sysname,@i)+'' ''+char(@i) select @i=@i+1 end */ declare @i int,@p sysname select @s=convert(varchar(4000),@s) select @p=''%[^''''=a-zA-Z0-9!-~ -]%'' -- select @p=''%[^!-~ ]%'' select @i = patindex(@p, @s) while @i > 0 begin select @s = replace(@s, substring(@s, @i, 1), '' '') select @i = patindex(@p, @s) end return @s end -- fn__str_print' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_print: -- =============================================================== fn__str_quote select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_quote',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120724 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_quote') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_quote') with nowait goto skip_fn__str_quote end if @ver>120724 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_quote') with nowait goto skip_fn__str_quote end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_quote') with nowait if exists( select top 1 null from sys.objects where name='fn__str_quote' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_quote] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120724\s.zaglio: modified to complete left or right quote v:111205\s.zaglio: specialized injection only for single&double quote v:090529\S.Zaglio: revision v:080505\S.Zaglio: close string into quotes if not just done and inject t: select dbo.fn__str_quote(''test'',''''''''),dbo.fn__str_quote(''test''''1'','''''''') t: select dbo.fn__str_quote(''''''test'''''',''''''''),dbo.fn__str_quote(''''''test''''''''1'','''''''') t: select dbo.fn__str_quote(''test'',''<>'') --> t: select dbo.fn__str_quote(null,''<>'') --> null t: select dbo.fn__str_quote(''test|'',''|''),dbo.fn__str_quote(''|test'',''|'') */ CREATE function [dbo].[fn__str_quote]( @str nvarchar(4000), @quotes nvarchar(4) -- single '', double " or couple () ) returns nvarchar(4000) as begin if @str is null return null declare @qo nvarchar(2),@qoe bit -- Quote Open Exists declare @qc nvarchar(2),@qce bit -- Quote Close Exists if len(@quotes)=1 select @qo=@quotes,@qc=@qo if len(@quotes)=2 select @qo=left(@quotes,1),@qc=right(@quotes,1) if left(@str,1) =@qo select @qoe=1 else select @qoe=0 if right(@str,1)=@qc select @qce=1 else select @qce=0 if @qo=@qc and @qo in ('''''''',''"'') select @str=replace(@str,@qo,@qo+@qo) -- inject if @qoe=0 select @str=@qo+@str if @qce=0 select @str=@str+@qc return @str end -- [fn__str_quote]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_quote: -- ============================================================== fn__str_remove select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_remove',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081110 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_remove') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_remove') with nowait goto skip_fn__str_remove end if @ver>081110 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_remove') with nowait goto skip_fn__str_remove end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_remove') with nowait if exists( select top 1 null from sys.objects where name='fn__str_remove' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_remove] begin try exec dbo.sp_executesql @statement = N'/* LEAVE THIS l:see LICENSE file g:utility v:081110\S.Zaglio: expanded @seps to nvarchar(32) v:080730\S.Zaglio: remove words from group t:print dbo.fn__str_remove(''a|b|c'',''a'',''|'') -->b|c t:print dbo.fn__str_remove(''a|b|c'',''a|c'',''|'') -->b t:print dbo.fn__str_remove(''a|b|c'',''d'',''|'') -->a|b|c t:print isnull(dbo.fn__str_remove(''a|b|c'',''a|b|c'',''|''),''(null)'') -->'''' */ CREATE function fn__str_remove(@tokens nvarchar(4000), @remove nvarchar(4000),@sep nvarchar(32)=''|'') returns nvarchar(4000) as begin /* declare @tokens nvarchar(4000) declare @remove nvarchar(4000) declare @sep nvarchar(8) set @sep=''|'' set @tokens=''a|b|c'' set @remove=''a'' */ declare @n int declare @r nvarchar(4000) set @r='''' declare @i int declare @k int declare @token sysname set @n=dbo.fn__str_count(@tokens,@sep) set @i=1 while (@i<=@n) begin set @token=dbo.fn__str_at(@tokens,@sep,@i) set @k=dbo.fn__at(@token,@remove,@sep) if @k=0 begin if @r<>'''' set @r=@r+@sep set @r=@r+@token end -- if set @i=@i+1 end -- while return @r end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_remove: -- ============================================================= fn__str_replace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_replace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_replace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_replace') with nowait goto skip_fn__str_replace end if @ver>120117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_replace') with nowait goto skip_fn__str_replace end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_replace') with nowait if exists( select top 1 null from sys.objects where name='fn__str_replace' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_replace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120117\s.zaglio: func version of sp__str_replace t: select dbo.fn__str_replace( ''test %r% and %p% and %c%'', ''%r%|%c%|%p%'', 1,getdate(),''a'', default,default,default,default,default,default,default,default ) */ create function fn__str_replace( @sentence nvarchar(4000)=null, @tokens nvarchar(4000)=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @p5 sql_variant=null, @p6 sql_variant=null, @p7 sql_variant=null, @p8 sql_variant=null, @p9 sql_variant=null, @p0 sql_variant=null, @sep nvarchar(32) ) returns nvarchar(4000) as begin declare @tk1 sysname,@tk2 sysname,@tk3 sysname,@tk4 sysname,@tk5 sysname, @tk6 sysname,@tk7 sysname,@tk8 sysname,@tk9 sysname,@tk0 sysname select @sep=isnull(@sep,''|'') select @tk1=case when pos=1 then token else @tk1 end, @tk2=case when pos=2 then token else @tk2 end, @tk3=case when pos=3 then token else @tk3 end, @tk4=case when pos=4 then token else @tk4 end, @tk5=case when pos=5 then token else @tk5 end, @tk6=case when pos=6 then token else @tk6 end, @tk7=case when pos=7 then token else @tk7 end, @tk8=case when pos=8 then token else @tk8 end, @tk9=case when pos=9 then token else @tk9 end, @tk0=case when pos=10 then token else @tk0 end from dbo.fn__str_table(@tokens,@sep) t /* return isnull(@tk1,''tk1'')+''|''+isnull(@tk2,''tk2'')+''|'' +isnull(@tk3,''tk3'')+''|''+isnull(@tk4,''tk4'')+''|'' +isnull(@tk5,''tk5'')+''|''+isnull(@tk6,''tk6'')+''|'' +isnull(@tk7,''tk7'')+''|''+isnull(@tk8,''tk8'')+''|'' +isnull(@tk9,''tk9'')+''|''+isnull(@tk0,''tk0'')+''|'' */ if not @tk1 is null select @sentence=replace(@sentence,@tk1,convert(nvarchar(4000),@p1)) if not @tk2 is null select @sentence=replace(@sentence,@tk2,convert(nvarchar(4000),@p2)) if not @tk3 is null select @sentence=replace(@sentence,@tk3,convert(nvarchar(4000),@p3)) if not @tk4 is null select @sentence=replace(@sentence,@tk4,convert(nvarchar(4000),@p4)) if not @tk5 is null select @sentence=replace(@sentence,@tk5,convert(nvarchar(4000),@p5)) if not @tk6 is null select @sentence=replace(@sentence,@tk6,convert(nvarchar(4000),@p6)) if not @tk7 is null select @sentence=replace(@sentence,@tk7,convert(nvarchar(4000),@p7)) if not @tk8 is null select @sentence=replace(@sentence,@tk8,convert(nvarchar(4000),@p8)) if not @tk9 is null select @sentence=replace(@sentence,@tk9,convert(nvarchar(4000),@p9)) if not @tk0 is null select @sentence=replace(@sentence,@tk0,convert(nvarchar(4000),@p0)) return @sentence end -- fn__str_replace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_replace: -- ============================================================ fn__str_scramble select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_scramble',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110527 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_scramble') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_scramble') with nowait goto skip_fn__str_scramble end if @ver>110527 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_scramble') with nowait goto skip_fn__str_scramble end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_scramble') with nowait if exists( select top 1 null from sys.objects where name='fn__str_scramble' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_scramble] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110527\S.Zaglio: a remake (the older will be a str generator) v:091018\s.zaglio: added scramble for numbers or chars only and a bug on len v:081218\S.Zaglio: scramble data c:remake of previous fun with same name t: select dbo.fn__str_scramble(''stefano zaglio'', rand(checksum(newid())) ) as [stefano zaglio], dbo.fn__str_scramble(''stefano zaglio'', rand(checksum(newid())) ) as [stefano zaglio], dbo.fn__str_scramble(''zaglio stefano'', rand(checksum(newid())) ) as [zaglio stefano], dbo.fn__str_scramble(''zaglio stefania'', rand(checksum(newid())) ) as [zaglio stefania] */ CREATE function fn__str_scramble(@data nvarchar(4000),@rand real) returns nvarchar(4000) as begin -- declare @data sysname select @data=''stefano zaglio'' declare @len int, @i int, -- index @p int, -- random position, @n int, @c nvarchar(1), @s int -- declare @len int select @len=10 -- declare @len int declare @rnd table(id int identity,r int) /* select top 32 ''union all select ''+convert(sysname,(RAND(CHECKSUM(NEWID()))))+''*@len+1'' from sysobjects SELECT CAST(CAST(newid() AS binary(1)) AS int)/256.0 select RAND(CHECKSUM(NEWID())) DECLARE @maxRandomValue TINYINT, @minRandomValue TINYINT select @maxRandomValue = 100, @minRandomValue = 0 SELECT CAST(((@maxRandomValue + 1) - @minRandomValue) * RAND(CHECKSUM(NEWID())) + @minRandomValue AS TINYINT) AS ''randomNumber'' */ select @len=len(@data),@i=1,@n=32,@s=20*@rand insert @rnd(r) -- declare @len int select @len=10 select 0.648147*@len+1 union all select 0.49276*@len+1 union all select 0.760752*@len+1 union all select 0.92745*@len+1 union all select 0.550134*@len+1 union all select 0.327785*@len+1 union all select 0.223983*@len+1 union all select 0.602884*@len+1 union all select 0.611201*@len+1 union all select 0.920175*@len+1 union all select 0.626131*@len+1 union all select 0.666639*@len+1 union all select 0.490854*@len+1 union all select 0.714348*@len+1 union all select 0.931448*@len+1 union all select 0.202067*@len+1 union all select 0.136386*@len+1 union all select 0.400647*@len+1 union all select 0.33078*@len+1 union all select 0.169345*@len+1 union all select 0.227007*@len+1 union all select 0.293043*@len+1 union all select 0.916565*@len+1 union all select 0.816953*@len+1 union all select 0.923834*@len+1 union all select 0.873596*@len+1 union all select 0.379763*@len+1 union all select 0.857231*@len+1 union all select 0.468347*@len+1 union all select 0.351739*@len+1 union all select 0.445449*@len+1 union all select 0.860574*@len+1 -- select * from @rnd while (@i<=@len) begin select @c=substring(@data,@i,1), @p=isnull((select r from @rnd where id=(@i+@s)%@n),1), @data=stuff(@data,@i,1,substring(@data,@p,1)), @data=stuff(@data,@p,1,@c), @i=@i+1 -- select @c c,@p p,@data data,@i i,@n n end return substring(''abcdefghijklmnopqrstuvwxyz'',@s,1)+@data end -- fn__str_scramble' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_scramble: -- ============================================================ fn__str_simplify select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_simplify',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090624 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_simplify') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_simplify') with nowait goto skip_fn__str_simplify end if @ver>090624 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_simplify') with nowait goto skip_fn__str_simplify end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_simplify') with nowait if exists( select top 1 null from sys.objects where name='fn__str_simplify' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_simplify] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090624\s.zaglio: default left/right trim v:081016\S.Zaglio: remove initila crlf and spaces v:080814\S.Zaglio: added replace of CRLF+SPACE to CRLF and corrected a bug nchar(13)->char(10) v:080812\S.Zaglio: added replace of SPACE+CRLF to CRLF v:080717\S.Zaglio: added @trim (1=left,2=left,0=left&right) v:080401\S.Zaglio: remove double spaces, crlf, tabs t:print ''|''+dbo.fn__str_simplify('' test 2space 3space '',default)+''|'' t:print ''|''+dbo.fn__str_simplify('' test 2space 3space '',1)+''|'' */ CREATE function fn__str_simplify(@str nvarchar(4000),@trim smallint=0) returns nvarchar(4000) as begin declare @crlf nchar(2) set @crlf=char(13)+char(10) if @trim=1 set @str=ltrim(@str) if @trim=2 set @str=rtrim(@str) if @trim=0 set @str=ltrim(rtrim(@str)) while left(@str,2)=@crlf set @str=substring(@str,3,len(@str)) while isnull(charindex(nchar(9), @str),0)>0 set @str=replace(@str,char(9), '' '') while isnull(charindex(@crlf+@crlf, @str),0)>0 set @str=replace(@str,@crlf+@crlf, @crlf) while isnull(charindex('' '', @str),0)>0 set @str=replace(@str,'' '', '' '') while isnull(charindex('' '', @str),0)>0 set @str=replace(@str,'' '', '' '') while isnull(charindex('' ''+@crlf, @str),0)>0 set @str=replace(@str,'' ''+@crlf, @crlf) while isnull(charindex(@crlf+'' '', @str),0)>0 set @str=replace(@str,@crlf+'' '', @crlf) while isnull(charindex('' ''+@crlf+'' '', @str),0)>0 set @str=replace(@str,'' ''+@crlf+'' '', @crlf) return @str end -- fn__str_simplify' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_simplify: -- ============================================================= fn__str_unquote select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__str_unquote',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120914 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__str_unquote') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__str_unquote') with nowait goto skip_fn__str_unquote end if @ver>120914 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__str_unquote') with nowait goto skip_fn__str_unquote end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_unquote') with nowait if exists( select top 1 null from sys.objects where name='fn__str_unquote' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__str_unquote] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:120914\s.zaglio: a small bug if len(@str)=1 v:100112\S.Zaglio: unquote with specification t:print dbo.fn__str_unquote(''[test]'',''[]'') */ CREATE function [dbo].[fn__str_unquote]( @str nvarchar(4000), @quotes nvarchar(4) -- single '', double " or couple () ) returns nvarchar(4000) as begin if @str is null return null declare @qo nvarchar(2) declare @qc nvarchar(2) declare @l int,@lr int,@ll int if len(@str)<2 return @str select @l=len(@quotes) if @l=1 begin set @qo=@quotes set @qc=@qo end if @l=2 begin set @qo=left(@quotes,1) set @qc=right(@quotes,1) end select @lr=len(@qo),@ll=len(@qc),@l=len(@str) if left(@str,1)=@qo and right(@str,1)=@qc begin select @str=substring(@str,@lr+1,@l-@lr-@ll) select @str=replace(@str,@qo+@qo,@qo) -- un-inject end return @str end -- [fn__str_unquote]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__str_unquote: -- =================================================================== fn__subst select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__subst',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080430 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__subst') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__subst') with nowait goto skip_fn__subst end if @ver>080430 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__subst') with nowait goto skip_fn__subst end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__subst') with nowait if exists( select top 1 null from sys.objects where name='fn__subst' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__subst] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080430\S.Zaglio: @action=1->left part of string from @from t: print dbo.fn__subst(default,''CREATE_SYNC_STRUCTURE:[gamon.seldom.it].ramsesbg'','':'',default) */ CREATE function fn__subst(@action tinyint=1,@str nvarchar(4000),@from nvarchar(8),@dummy nvarchar(4000)=null) returns nvarchar(4000) as begin return substring(@str,isnull(charindex(@from,@str)+len(@from),len(@str)),len(@str)) end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__subst: -- ====================================================================== fn__t9 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__t9',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090609 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__t9') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__t9') with nowait goto skip_fn__t9 end if @ver>090609 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__t9') with nowait goto skip_fn__t9 end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__t9') with nowait if exists( select top 1 null from sys.objects where name='fn__t9' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__t9] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090609\S.Zaglio: adapted to sqlce v:061226\S.Zaglio: get like expression on keys pressed t:print dbo.fn__t9(''cod'',''.1234567890'') */ CREATE function [dbo].[fn__t9](@fld sysname, @t9 nvarchar(32)) returns nvarchar(4000) as begin /* select top 5 * from table where 1=1 -- search for t9:23 and (cod like ''a%'' or cod like ''b%'' or cod like ''c%'' or cod like ''2%'') and (cod like ''_d%'' or cod like ''_e%'' or cod like ''_f%'' or cod like ''_3%'') and ... */ declare @r nvarchar(4000) set @r='''' declare @c nchar(1) declare @s sysname,@chars sysname declare @i int, @j int , @l int select @i=1,@l=len(@t9) while (@i<=@l) begin select @r=@r+case @i when @l then '' and (('' else '' and ('' end select @c=substring(@t9,@i,1) select @j=@i-1,@s='''' while (@j>0) select @s=@s+N''_'',@j=@j-1 set @chars = case @c when ''0'' then ''0'' when ''1'' then ''1'' when ''2'' then ''cba2'' when ''3'' then ''fed3'' when ''4'' then ''ihg4'' when ''5'' then ''lkj5'' when ''6'' then ''onm6'' when ''7'' then ''srqp7'' when ''8'' then ''vut8'' when ''9'' then ''zyxw9'' else ''_'' end -- case select @j=len(@chars) while (@j>0) begin select @r=@r+@fld+'' like ''''''+@s+substring(@chars,@j,1)+''%'''''',@j=@j-1 if @j>0 select @r=@r+'' or '' end set @r=@r+'')'' set @i=@i+1 end -- while i090430 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__t9_cmp') with nowait goto skip_fn__t9_cmp end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__t9_cmp') with nowait if exists( select top 1 null from sys.objects where name='fn__t9_cmp' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__t9_cmp] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090430\s.zaglio */ CREATE function fn__t9_cmp(@t9_src int, @len tinyint, @t9_key int) returns bit as begin if convert(int,left(convert(varchar(12),@t9_key),@len))=@t9_src return 1 return 0 end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__t9_cmp: -- ================================================================== fn__t9_key select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__t9_key',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090430 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__t9_key') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__t9_key') with nowait goto skip_fn__t9_key end if @ver>090430 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__t9_key') with nowait goto skip_fn__t9_key end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__t9_key') with nowait if exists( select top 1 null from sys.objects where name='fn__t9_key' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__t9_key] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090430\S.Zaglio: revision: added @max_len and set result to bigint */ CREATE function [dbo].[fn__t9_key](@string nvarchar(4000),@max_len tinyint=9) returns bigint as begin declare @c nvarchar(1) declare @i int set @i=1 declare @r bigint set @r=0 if @max_len>19 set @max_len=19 while (@i<=@max_len and @i<=len(@string)) begin set @r=@r*10 set @c=substring(@string,@i,1) set @i=@i+1 if @c=''0'' and @i=1 begin set @r=-@r continue end if @c=''1'' begin set @r=@r+1 continue end if @c like ''[2abc]'' begin set @r=@r+2 continue end if @c like ''[3def]'' begin set @r=@r+3 continue end if @c like ''[4ghi]'' begin set @r=@r+4 continue end if @c like ''[5jkl]'' begin set @r=@r+5 continue end if @c like ''[6mno]'' begin set @r=@r+6 continue end if @c like ''[7pqrs]'' begin set @r=@r+7 continue end if @c like ''[8tuv]'' begin set @r=@r+8 continue end if @c like ''[9wxyz]'' begin set @r=@r+9 continue end end -- while return @r end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__t9_key: -- ================================================================= fn__t9_vkey select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__t9_vkey',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090430 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__t9_vkey') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__t9_vkey') with nowait goto skip_fn__t9_vkey end if @ver>090430 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__t9_vkey') with nowait goto skip_fn__t9_vkey end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__t9_vkey') with nowait if exists( select top 1 null from sys.objects where name='fn__t9_vkey' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__t9_vkey] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090430/S.Zaglio: revision: added @max_len and set result to bigint */ create function [dbo].[fn__t9_vkey](@string nvarchar(4000),@max_len tinyint=9) returns nvarchar(32) as begin declare @c nvarchar(1) declare @i int set @i=1 declare @r nvarchar(32) set @r='''' if @max_len>19 set @max_len=19 while (@i<=@max_len and @i<=len(@string)) begin set @c=substring(@string,@i,1) set @i=@i+1 if @c like ''[1*]'' begin set @r=@r+''1'' continue end if @c like ''[2abc]'' begin set @r=@r+''2'' continue end if @c like ''[3def]'' begin set @r=@r+''3'' continue end if @c like ''[4ghi]'' begin set @r=@r+''4'' continue end if @c like ''[5jkl]'' begin set @r=@r+''5'' continue end if @c like ''[6mno]'' begin set @r=@r+''6'' continue end if @c like ''[7pqrs]'' begin set @r=@r+''7'' continue end if @c like ''[8tuv]'' begin set @r=@r+''8'' continue end if @c like ''[9wxyz]'' begin set @r=@r+''9'' continue end set @r=@r+''0'' -- normalize for everything not recodnized end -- while return @r end -- function' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__t9_vkey: -- ============================================================== fn__taxcode_it select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__taxcode_it',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130830 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__taxcode_it') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__taxcode_it') with nowait goto skip_fn__taxcode_it end if @ver>130830 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__taxcode_it') with nowait goto skip_fn__taxcode_it end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__taxcode_it') with nowait if exists( select top 1 null from sys.objects where name='fn__taxcode_it' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__taxcode_it] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility d:130830\s.zaglio: fn__taxcode v:130830\s.zaglio: renamed into fn__taxcode_it v:101209\d.averoldi: corrected some bug v:101208\s.zaglio: calculate italian TAX code (only for check, not really legal) c:from http://microsoft-it.confusenet.com/showthread.php?t=16620 t:select dbo.fn__taxcode(''Stefano'', ''Zaglio'', 1, ''19720201'', ''X000'') --> ZGLSFN72B01X000R t:select dbo.fn__taxcode(''Davide'', ''Averoldi'', 1, '''', ''X000'') --> --> VRLDVD00A01X000W */ create function fn__taxcode_it( @first_name varchar(255), @last_name varchar(255), @male bit, -- 1=male 0=female @birth_day datetime, -- yyyymmdd @region_code char(4)) -- http://it.wikipedia.org/wiki/Codice_catastale returns varchar(16) as begin declare @tax varchar(16) set @tax='''' /* -- TEST -- declare @d datetime set @d=getdate() select dbo.fn__GetCf(''paolo'', ''Bigongiari'', 1, @d, ''c124'') */ /* Cognome (3 lettere) Vengono prese le consonanti del cognome (o dei cognomi, se ve ne è più di uno) nel loro ordine: solo se sono insufficienti, si prelevano anche le vocali, sempre nel loro ordine: comunque, le vocali vengono riportate dopo le consonanti. Nel caso in cui un cognome abbia meno di tre lettere, la parte di codice viene completata aggiungendo la lettera X (es.: Fo -> FOX). Per le donne, viene preso in considerazione il solo cognome da nubile. */ set @last_name=replace(@last_name, '' '', '''') set @last_name=replace(@last_name, '''''''', '''') if @last_name like ''%[^a-z]%'' return null if @last_name='''' return null; declare @T table(L char(1) not null, R varchar(255) not null, N int primary key, N2 int not null, Vocale as case when L in(''a'', ''e'', ''i'', ''o'', ''u'') then 1 else 0 end ) insert into @T select L = left(@last_name,1), R = stuff(@last_name, 1, 1, ''''), N=1, 0 while (select max(N) from @T) < len(@last_name) begin insert into @T select top 1 L = left(R,1), R = stuff(R, 1, 1, ''''), N=N+1, 0 from @T order by N desc if @@rowcount=0 break end; select top 3 @tax = @tax + L from @T x order by Vocale, N set @tax = left(@tax + ''xx'', 3); /* Nome (3 lettere) Vengono prese le consonanti del nome (o dei nomi, se ve ne è più di uno) in questo modo: se il nome contiene quattro o più consonanti, si scelgono la prima, la terza e la quarta, altrimenti le prime tre in ordine. Solo se il nome non ha consonanti a sufficienza, si prendono anche le vocali: comunque, le vocali vengono riportate dopo le consonanti. Nel caso in cui il nome abbia meno di tre lettere, la parte di codice viene completata aggiungendo la lettera X. Un caso estremo si incontra in alcuni soggetti provenienti dall''India nel passaporto dei quali è riportata una sola parola al posto del cognome e del nome. Si userà allora quella parola per generare le prime tre lettere del codice e, non esistendo il nome, la seconda terzina di lettere del codice sarà XXX. */ set @first_name=replace(@first_name, '' '', '''') set @first_name=replace(@first_name, '''''''', '''') if @first_name like ''%[^a-z]%'' return null; delete @T; if @first_name>'''' begin insert into @T select L = left(@first_name,1), R = stuff(@first_name, 1, 1, ''''), N=1, 0 while (select max(N) from @T) < len(@first_name) begin insert into @T select top 1 L = left(R,1), R = stuff(R, 1, 1, ''''), N=N+1, 0 from @T order by N desc if @@rowcount=0 break end; end declare @Cs int select @Cs=count(*) from @T where Vocale=0 update @T set N2=case t.Vocale when 0 then t.N-K else t.N-K + @Cs end from @T t inner join( select t1.N, K=sum(isnull(t2.Vocale,0)) from @T t1 left outer join @T t2 on t2.N */ delete @T; insert into @T select L = left(@tax,1), R = stuff(@tax, 1, 1, ''''), N=1, 0 while (select max(N) from @T) < len(@tax) begin insert into @T select top 1 L = left(R,1), R = stuff(R, 1, 1, ''''), N=N+1, 0 from @T order by N desc if @@rowcount=0 break end; select @tax = @tax + char(97+k) from ( select k=sum(case N%2 when 1 then case L when ''0'' then 1 when ''9'' then 21 when ''I'' then 19 when ''R'' then 8 when ''1'' then 0 when ''A'' then 1 when ''J'' then 21 when ''S'' then 12 when ''2'' then 5 when ''B'' then 0 when ''K'' then 2 when ''T'' then 14 when ''3'' then 7 when ''C'' then 5 when ''L'' then 4 when ''U'' then 16 when ''4'' then 9 when ''D'' then 7 when ''M'' then 18 when ''V'' then 10 when ''5'' then 13 when ''E'' then 9 when ''N'' then 20 when ''W'' then 22 when ''6'' then 15 when ''F'' then 13 when ''O'' then 11 when ''X'' then 25 when ''7'' then 17 when ''G'' then 15 when ''P'' then 3 when ''Y'' then 24 when ''8'' then 19 when ''H'' then 17 when ''Q'' then 6 when ''Z'' then 23 end else case L when ''0'' then 0 when ''9'' then 9 when ''I'' then 8 when ''R'' then 17 when ''1'' then 1 when ''A'' then 0 when ''J'' then 9 when ''S'' then 18 when ''2'' then 2 when ''B'' then 1 when ''K'' then 10 when ''T'' then 19 when ''3'' then 3 when ''C'' then 2 when ''L'' then 11 when ''U'' then 20 when ''4'' then 4 when ''D'' then 3 when ''M'' then 12 when ''V'' then 21 when ''5'' then 5 when ''E'' then 4 when ''N'' then 13 when ''W'' then 22 when ''6'' then 6 when ''F'' then 5 when ''O'' then 14 when ''X'' then 23 when ''7'' then 7 when ''G'' then 6 when ''P'' then 15 when ''Y'' then 24 when ''8'' then 8 when ''H'' then 7 when ''Q'' then 16 when ''Z'' then 25 end end)%26 from @T x )s return upper(@tax) end -- fn__taxcode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__taxcode_it: -- ==================================================================== fn__time select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__time',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=111215 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__time') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__time') with nowait goto skip_fn__time end if @ver>111215 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__time') with nowait goto skip_fn__time end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__time') with nowait if exists( select top 1 null from sys.objects where name='fn__time' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__time] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:time v:111215\s.zaglio: when hour is ss.000, 126 strip to ss v:111004\s.zaglio: return a float with time of datetime. decimals as ms t:select dbo.fn__time(getdate()) */ CREATE function fn__time(@dt datetime) returns float as begin declare @f float,@s varchar(32) select @s=right(convert(varchar(32),@dt,114),12) select @f=convert(float,replace(left(@s,8),'':'','''')+''.''+right(@s,3)) return @f end -- fn__time' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__time: -- =============================================================== fn__token_sql select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__token_sql',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=111128 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__token_sql') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__token_sql') with nowait goto skip_fn__token_sql end if @ver>111128 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__token_sql') with nowait goto skip_fn__token_sql end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__token_sql') with nowait if exists( select top 1 null from sys.objects where name='fn__token_sql' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__token_sql] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:111128\s.zaglio: added key v:101230\s.zaglio: added option v:091128\s.zaglio: commonly used by fn__flds_quotename and sp__token */ CREATE function fn__token_sql(@name sysname) returns bit as begin if @name is null return null if @name in (''delete'',''id'',''select'',''insert'',''update'',''name'',''group'',''backup'',''default'', ''set'',''table'',''view'',''as'',''where'',''from'',''to'',''go'',''by'',''having'',''create'', ''nocount'',''on'',''begin'',''end'',''if'',''else'',''exec'',''declare'',''return'', ''bit'',''nvarchar'',''varchar'',''int'',''bigint'',''char'',''nchar'',''sysname'',''datetime'', ''top'',''proc'',''function'',''goto'',''drop'',''not'',''is'',''null'',''option'',''key'' ) return 1 return 0 end -- fn__token_sql' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__token_sql: -- ==================================================================== fn__trim select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__trim',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=070701 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__trim') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__trim') with nowait goto skip_fn__trim end if @ver>070701 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__trim') with nowait goto skip_fn__trim end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__trim') with nowait if exists( select top 1 null from sys.objects where name='fn__trim' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__trim] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:070701\S.Zaglio: remove left and right spaces t:print dbo.fn__trim(convert(nchar(20),'' hello '')) */ create function fn__trim(@st nvarchar(4000)) returns nvarchar(4000) as begin return ltrim(rtrim(@st)) end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__trim: -- ========================================================== fn__unix_timestamp select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__unix_timestamp',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120823 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__unix_timestamp') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__unix_timestamp') with nowait goto skip_fn__unix_timestamp end if @ver>120823 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__unix_timestamp') with nowait goto skip_fn__unix_timestamp end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__unix_timestamp') with nowait if exists( select top 1 null from sys.objects where name='fn__unix_timestamp' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__unix_timestamp] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:120823\s.zaglio: convert datetime to unix format t:select fn__unix_timestamp(getdate()) */ CREATE function fn__unix_timestamp ( @dt datetime ) returns integer as begin declare @ret int select @ret = datediff(s,{d ''1970-01-01''}, @dt) return @ret end -- fn__unix_timestamp' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__unix_timestamp: -- ========================================================= fn__web_html_decode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__web_html_decode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130922 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__web_html_decode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__web_html_decode') with nowait goto skip_fn__web_html_decode end if @ver>130922 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__web_html_decode') with nowait goto skip_fn__web_html_decode end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__web_html_decode') with nowait if exists( select top 1 null from sys.objects where name='fn__web_html_decode' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__web_html_decode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130922\s.zaglio: @vcresult qas nv max v:121018\s.zaglio: decode url t:select dbo.fn__web_html_decode( */ CREATE function fn__web_html_decode (@vcwhat nvarchar(max)) returns nvarchar(max) as begin declare @vcresult nvarchar(max) declare @vccrlf varchar(2) declare @sipos smallint,@vcencoded varchar(7),@sichar smallint select @vccrlf=crlf from fn__sym() select @vcresult=@vcwhat select @sipos=patindex(''%&#___;%'',@vcresult) while @sipos>0 begin select @vcencoded=substring(@vcresult,@sipos,6) select @sichar=cast(substring(@vcencoded,3,3) as smallint) select @vcresult=replace(@vcresult,@vcencoded,nchar(@sichar)) select @sipos=patindex(''%&#___;%'',@vcresult) end select @sipos=patindex(''%&#____;%'',@vcresult) while @sipos>0 begin select @vcencoded=substring(@vcresult,@sipos,7) select @sichar=cast(substring(@vcencoded,3,4) as smallint) select @vcresult=replace(@vcresult,@vcencoded,nchar(@sichar)) select @sipos=patindex(''%&#____;%'',@vcresult) end select @vcResult=replace(@vcResult,''"'',''"'') select @vcResult=replace(@vcResult,''&'',''&'') select @vcResult=replace(@vcResult,''©'',''©'') select @vcResult=replace(@vcResult,''«'',''«'') select @vcResult=replace(@vcResult,''»'',''»'') select @vcResult=replace(@vcResult,''¼'',''¼'') select @vcResult=replace(@vcResult,''½'',''½'') select @vcResult=replace(@vcResult,''¿'',''¿'') select @vcResult=replace(@vcResult,''<'',''<'') select @vcResult=replace(@vcResult,''>'',''>'') select @vcresult=replace(@vcresult,''

'',@vccrlf) return @vcresult end -- fn__web_html_decode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__web_html_decode: -- ========================================================== fn__web_url_decode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__web_url_decode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__web_url_decode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__web_url_decode') with nowait goto skip_fn__web_url_decode end if @ver>121018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__web_url_decode') with nowait goto skip_fn__web_url_decode end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__web_url_decode') with nowait if exists( select top 1 null from sys.objects where name='fn__web_url_decode' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__web_url_decode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,web v:121018\s.zaglio: decode url t:select dbo.fn__web_url_decode(''jeff%2Bsmith'') */ CREATE function fn__web_url_decode(@url nvarchar(4000)) returns nvarchar(4000) as begin -- from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=88926 declare @position int, @base char(16), @high tinyint, @low tinyint, @pattern char(21) select @base = ''0123456789abcdef'', @pattern = ''%[%][0-9a-f][0-9a-f]%'', @url = replace(@url, ''+'', '' ''), @position = patindex(@pattern, @url) while @position > 0 select @high = charindex(substring(@url, @position + 1, 1), @base), @low = charindex(substring(@url, @position + 2, 1), @base), @url = stuff(@url, @position, 3, char(16 * @high + @low - 17)), @position = patindex(@pattern, @url) return @url end -- fn__web_url_decode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__web_url_decode: -- ========================================================== fn__web_url_encode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__web_url_encode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__web_url_encode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__web_url_encode') with nowait goto skip_fn__web_url_encode end if @ver>121018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__web_url_encode') with nowait goto skip_fn__web_url_encode end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__web_url_encode') with nowait if exists( select top 1 null from sys.objects where name='fn__web_url_encode' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__web_url_encode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,web v:121018\s.zaglio: encode url t:select dbo.fn__web_url_encode(''8ECEE9BE-05BD-4DD2-9D09-6C121E0924E7'') */ CREATE function dbo.fn__web_url_encode(@strInput nvarchar(4000)) returns nvarchar(4000) as begin -- from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=88926 return replace(replace(replace(replace(replace( replace(replace(replace(replace(replace( replace(replace(replace(replace(replace( replace(replace(replace(replace(replace( replace(replace(replace(replace(replace( replace(replace( @strInput, ''%'', ''%25''), char(10), ''%0A''), char(13), ''%0D''), '' '', ''%20''), '':'', ''%3A''), '';'', ''%3B''), ''-'', ''%2D''), ''/'', ''%2F''), ''\'', ''%5C''), ''!'', ''%21''), ''"'', ''%22''), ''#'', ''%23''), ''?'', ''%3F''), ''='', ''%3D''), ''@'', ''%40''), ''>'', ''%3E''), ''<'', ''%3C''), ''$'', ''%24''), ''&'', ''%26''), ''['', ''%5B''), '']'', ''%5D''), ''~'', ''%7E''), ''^'', ''%5E''), ''`'', ''%60''), ''{'', ''%7B''), ''}'', ''%7D''), ''|'', ''%7C'') end -- fn__web_url_encode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__web_url_encode: -- =============================================================== fn__word_find select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__word_find',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090815 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__word_find') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__word_find') with nowait goto skip_fn__word_find end if @ver>090815 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__word_find') with nowait goto skip_fn__word_find end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__word_find') with nowait if exists( select top 1 null from sys.objects where name='fn__word_find' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__word_find] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090815\s.zaglio: find a word in a sentence t:print dbo.fn__word_find(''convert(nvarchar,@test)'',''varchar'',default,default) -->9 t:print dbo.fn__word_find(''declare @test nvarchar(10)'',''varchar'',default,default) -->15 t:print dbo.fn__word_find(''varchar 10'',''varchar'',default,default) ->1 t:print dbo.fn__word_find(''set nvarchar 10'',''varchar'',default,default) ->0 */ CREATE function [dbo].[fn__word_find]( @sentence nvarchar(4000), @word sysname, @lt sysname=null, @rt sysname=null ) returns int as begin declare @i int,@c nchar declare @key sysname declare @points sysname if @sentence is null return null select @points='' ([,])'' if @lt is null select @lt=@points+char(9) if @rt is null select @rt=@points+char(13) select @key=''%''+replace(replace(@word,''_'',''[_]''),''%'',''[%]'')+''%'' /* tests: print patindex(''%word%'',''wordcap'') -->1 print patindex(''%_word%'',''wordcap'') -->0 print patindex(''%_word%'',''inwordcap'') -->2 print patindex(''%word%'',''demoword'') -->5 if substring(''hello'',6,1)='''' print ''empty space'' -->empty space if substring(''hello'',-1,1)='''' print ''empty space'' -->empty space */ select @i=patindex(@key,@sentence) if @i=0 return 0 select @c=substring(@sentence,@i+len(@word),1) if @c!='''' and charindex(@c,@rt)=0 return 0 select @c=substring(@sentence,@i-1,1) if @c!='''' and charindex(@c,@lt)=0 return 0 return @i end -- function fn__word_find' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__word_find: -- =========================================================== fn__words_replace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__words_replace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090815 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__words_replace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__words_replace') with nowait goto skip_fn__words_replace end if @ver>090815 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__words_replace') with nowait goto skip_fn__words_replace end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__words_replace') with nowait if exists( select top 1 null from sys.objects where name='fn__words_replace' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__words_replace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090815\s.zaglio: find a word in a sentence t:print dbo.fn__words_replace( '' declare @v nvarchar(12) nchar @v=convert(nvarchar,@varchar)'', default, ''varchar|char'', ''nvarchar|nchar'', default, default) */ CREATE function [dbo].[fn__words_replace]( @sentence nvarchar(4000), @sep nvarchar(32)=''|'', @words sysname, @replaces sysname, @lt sysname=null, @rt sysname=null ) returns nvarchar(4000) as begin declare @i int,@l int,@j int,@n int, @word sysname,@replace sysname if @sentence is null return null select @j=1,@n=dbo.fn__str_count(@words,@sep) while @j<=@n begin select @word=dbo.fn__str_at(@words,@sep,@j) select @replace=dbo.fn__str_at(@replaces,@sep,@j) select @j=@j+1,@l=len(@word),@i=dbo.fn__word_find(@sentence,@word,@lt,@rt) while (@i>0) begin select @sentence=substring(@sentence,1,@i-1)+@replace+substring(@sentence,@i+@l,4000) select @i=dbo.fn__word_find(@sentence,@word,@lt,@rt) end -- while end -- while words return @sentence end -- function fn__word_find' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_fn__words_replace: -- ================================================================ fn__html_tag select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='fn__html_tag',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120823.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'fn__html_tag') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'fn__html_tag') with nowait goto skip_fn__html_tag end if @ver>120823.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'fn__html_tag') with nowait goto skip_fn__html_tag end end raiserror('re-creating "%s.%s"',10,1,@db,'fn__html_tag') with nowait if exists( select top 1 null from sys.objects where name='fn__html_tag' and schema_id=schema_id('dbo') ) drop function [dbo].[fn__html_tag] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:web v:120823.1000\s.zaglio: short comment c:from http://www.simple-talk.com c:/sql/t-sql-programming/getting-html-data-workbench/ t:select * from fn__html_tag() */ CREATE function fn__html_tag() returns table as return SELECT [tag]=''!DOCTYPE'', [meaning]=''Defines the document type'', [type]=''Basic Tag'',[HasclosingTag]=0 UNION SELECT ''!|[CDATA|['', ''delimits a javascript area in XHTML'',''Basic Tag'',0 --note we have used the ESCAPE char | before the ''['' character --as otherwise it would foul up the LIKE comparison UNION SELECT ''?xml'', ''flags an XML document'',''Basic Tag'',0 UNION SELECT ''html'', ''Defines a html document'',''Basic Tag'',1 UNION SELECT ''body'', ''Defines the body element'',''Basic Tag'',1 UNION SELECT ''h1'', ''Defines header 1 '',''Basic Tag'',1 UNION SELECT ''h2'', ''Defines header 2 '',''Basic Tag'',1 UNION SELECT ''h3'', ''Defines header 3 '',''Basic Tag'',1 UNION SELECT ''h4'', ''Defines header 4 '',''Basic Tag'',1 UNION SELECT ''h5'', ''Definess header 5 '',''Basic Tag'',1 UNION SELECT ''h6'', ''Defines header 6 '',''Basic Tag'',1 UNION SELECT ''p'', ''Defines a paragraph'',''Basic Tag'',1 UNION SELECT ''br'', ''Inserts a single line break'',''Basic Tag'',0 UNION SELECT ''hr'', ''Defines a horizontal rule'',''Basic Tag'',0 UNION SELECT ''!--'', ''Defines a comment'',''Basic Tag'',0 UNION SELECT ''b'', ''Defines bold text'',''Char Format'',1 UNION SELECT ''font'', ''Defines the font face, size, and color of text'', ''Char Format'',1 UNION SELECT ''i'', ''Defines italic text'',''Char Format'',1 UNION SELECT ''em'', ''Defines emphasized text '',''Char Format'',1 UNION SELECT ''big'', ''Defines big text'',''Char Format'',1 UNION SELECT ''strong'', ''Defines strong text'',''Char Format'',1 UNION SELECT ''small'', ''Defines small text'',''Char Format'',1 UNION SELECT ''sup'', ''Defines superscripted text'',''Char Format'',1 UNION SELECT ''sub'', ''Defines subscripted text'',''Char Format'',1 UNION SELECT ''bdo'', ''Defines the direction of text display'', ''Char Format'',1 UNION SELECT ''u'', ''Defines underlined text'',''Char Format'',1 UNION SELECT ''pre'', ''Defines preformatted text'',''Output'',1 UNION SELECT ''code'', ''Defines computer code text'',''Output'',1 UNION SELECT ''tt'', ''Defines teletype text'',''Output'',1 UNION SELECT ''kbd'', ''Defines keyboard text'',''Output'',1 UNION SELECT ''dfn'', ''Defines a definition term'',''Output'',1 UNION SELECT ''var'', ''Defines a variable'',''Output'',1 UNION SELECT ''samp'', ''Defines sample computer code'',''Output'',1 UNION SELECT ''xmp'', ''Deprecated. Use

 instead'',''Output'',1
UNION SELECT ''acronym'', ''Defines an acronym'',''Blocks'',1
UNION SELECT ''abbr'', ''Defines an abbreviation'',''Blocks'',1
UNION SELECT ''address'', ''Defines an address element'',''Blocks'',1
UNION SELECT ''blockquote'', ''Defines an long quotation'',''Blocks'',1
UNION SELECT ''center'', ''Defines centered text'',''Blocks'',1
UNION SELECT ''q'', ''Defines a short quotation'',''Blocks'',1
UNION SELECT ''cite'', ''Defines a citation'',''Blocks'',1
UNION SELECT ''ins'', ''Defines inserted text'',''Blocks'',1
UNION SELECT ''del'', ''Defines deleted text'',''Blocks'',1
UNION SELECT ''s'', ''Defines strikethrough text'',''Blocks'',1
UNION SELECT ''strike'', ''Defines strikethrough text'',''Blocks'',1
UNION SELECT ''a'', ''Defines an anchor'',''Links'',1
UNION SELECT ''link'', ''Defines a resource reference'',''Links'',0
UNION SELECT ''frame'', ''Defines a sub window (a frame)'',''Frames'',1
UNION SELECT ''frameset'', ''Defines a set of frames'',''Frames'',1
UNION SELECT ''noframes'', ''Defines a noframe section'',''Frames'',1
UNION SELECT ''iframe'', ''Defines an inline sub window (frame)'',''Frames'',1
UNION SELECT ''form'', ''Defines a form '',''Input'',1
UNION SELECT ''input'', ''Defines an input field'',''Input'',0
UNION SELECT ''textarea'', ''Defines a text area'',''Input'',1
UNION SELECT ''button'', ''Defines a push button'',''Input'',1
UNION SELECT ''select'', ''Defines a selectable list'',''Input'',1
UNION SELECT ''optgroup'', ''Defines an option group'',''Input'',1
UNION SELECT ''option'', ''Defines an item in a list box'',''Input'',1
UNION SELECT ''label'', ''Defines a label for a form control'',''Input'',1
UNION SELECT ''fieldset'', ''Defines a fieldset'',''Input'',1
UNION SELECT ''legend'', ''Defines a title in a fieldset'',''Input'',1
UNION SELECT ''isindex'', ''Deprecated. Use  instead'',''Input'',1
UNION SELECT ''ul'', ''Defines an unordered list'',''Lists'',1
UNION SELECT ''ol'', ''Defines an ordered list'',''Lists'',1
UNION SELECT ''li'', ''Defines a list item'',''Lists'',1
UNION SELECT ''dir'', ''Defines a directory list'',''Lists'',1
UNION SELECT ''dl'', ''Defines a definition list'',''Lists'',1
UNION SELECT ''dt'', ''Defines a definition term'',''Lists'',1
UNION SELECT ''dd'', ''Defines a definition description'',''Lists'',1
UNION SELECT ''menu'', ''Defines a menu list'',''Lists'',1
UNION SELECT ''img'', ''Defines an image'',''Images'',0
UNION SELECT ''map'', ''Defines an image map '',''Images'',1
UNION SELECT ''area'', ''Defines an area inside an image map'',''Images'',0
UNION SELECT ''table'', ''Defines a table'',''Tables'',1
UNION SELECT ''caption'', ''Defines a table caption'',''Tables'',1
UNION SELECT ''th'', ''Defines a table header'',''Tables'',1
UNION SELECT ''tr'', ''Defines a table row'',''Tables'',1
UNION SELECT ''td'', ''Defines a table cell'',''Tables'',1
UNION SELECT ''thead'', ''Defines a table header'',''Tables'',1
UNION SELECT ''tbody'', ''Defines a table body'',''Tables'',1
UNION SELECT ''tfoot'', ''Defines a table footer'',''Tables'',1
UNION SELECT ''col'', ''Defines attributes for table columns '',''Tables'',0
UNION SELECT ''colgroup'', ''Defines groups of table columns'',''Tables'',1
UNION SELECT ''style'', ''Defines a style definition'',''Styles'',1
UNION SELECT ''div'', ''Defines a section in a document'',''Styles'',1
UNION SELECT ''span'', ''Defines a section in a document'',''Styles'',1
UNION SELECT ''head'', ''Defines information about the document'',''Meta Info'',1
UNION SELECT ''title'', ''Defines the document title'',''Meta Info'',1
UNION SELECT ''meta'', ''Defines meta information'',''Meta Info'',0
UNION SELECT ''base'', ''Defines base URL for all links in a page'',''Meta Info'',0
UNION SELECT ''basefont'', ''Defines a base font'',''Meta Info'',0
UNION SELECT ''script'', ''Defines a script'',''Programming'',1
UNION SELECT ''noscript'', ''Defines a noscript section'',''Programming'',1
UNION SELECT ''applet'', ''Defines an applet'',''Programming'',1
UNION SELECT ''object'', ''Defines an embedded object'',''Programming'',1
UNION SELECT ''param'', ''Defines a parameter for an object'',''Programming'',0
-- fn__web_tag'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__html_tag:

-- ===================================================================== fn__job
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__job',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131215
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__job') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__job') with nowait
        goto skip_fn__job
        end
    if @ver>131215
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__job') with nowait
        goto skip_fn__job
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__job') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__job'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__job]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    o:130209.1000\s.zaglio: fn__isjob
    v:131215\s.zaglio: maybe more compatible with future versions of mssql
    v:130209.1000\s.zaglio: return job info about @@spid
    t:sp__job_test
*/
CREATE function fn__job(@spid int)
returns table
as
return
select top 1 job_id,name,loginame
-- select top 1 *
from master..sysprocesses ss
join msdb..sysjobs
on  rtrim(ltrim(dbo.fn__str_between(ss.program_name,''job '','' :'',default)))
    =
    dbo.fn__hex(convert(varbinary,job_id))
where spid=@spid
and left([program_name],8)=''SQLAgent''
and hostname=left(@@servername,len(hostname))    -- istance is not passed
/*    this is not really necessary
and ltrim(rtrim(loginame)) in (
    dbo.fn__job_agent(),        /*    this return different values:
                                    LocalSystem instead of NT AUTH..\SYSTEM
                                    names in system language instead of local */
    ''NT AUTHORITY\SYSTEM'',''SQLServerAgentSVC'',    -- mssql2k and 2k5
    ''SERVIZIO DI RETE'',                            -- italian lang
    ''servicesql''                                -- on mssql2k12
    )
*/
-- fn__job'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__job:

-- ================================================================ fn__place_at
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__place_at',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121016
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__place_at') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__place_at') with nowait
        goto skip_fn__place_at
        end
    if @ver>121016
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__place_at') with nowait
        goto skip_fn__place_at
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__place_at') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__place_at'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__place_at]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:street, place, constant, type, at
    v:121016\s.zaglio: list "at" type of places
    t:select * from fn__place_at()
*/
CREATE function fn__place_at()
returns table
with schemabinding
as
return
select 1 lng,1 id,0 rid,''C/O'' cod       -- presso
union select 1,2,1,''PRESSO''
union select 1,3,1,''P/O''       -- presso
union select 1,4,1,''CASA DI RIPOSO''
union select 1,5,1,''REPARTO''
union select 1,6,1,''CENTRO DI RIABILITAZIONE''
union select 1,7,1,''RSA''
union select 1,8,1,''C\O''

-- end fn__place_at'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__place_at:

-- ============================================================== fn__place_type
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__place_type',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121016
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__place_type') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__place_type') with nowait
        goto skip_fn__place_type
        end
    if @ver>121016
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__place_type') with nowait
        goto skip_fn__place_type
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__place_type') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__place_type'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__place_type]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:street, place, constant, type
    v:121016\s.zaglio: list type of places
    t:select * from fn__place_type()
*/
CREATE function fn__place_type()
returns table
with schemabinding
as
return
select 1 lng,1 id,0 rid,''CASELLA POSTALE'' cod
union select 1,2,0,''CONTRADA''
union select 1,3,0,''CORSO''
union select 1,4,0,''FRAZIONE''
union select 1,5,0,''LIDO''
union select 1,6,0,''LOCALITÀ''
union select 1,7,0,''LUNGOMARE''
union select 1,8,0,''MOLO''
union select 1,9,0,''OSPEDALE''
union select 1,10,0,''PASSEGGIATA''
union select 1,11,0,''PIAZZA''
union select 1,12,0,''RACCORDO''
union select 1,13,0,''RIONE''
union select 1,14,0,''SCALO''
union select 1,15,0,''STRADA''
union select 1,16,0,''STRADINA''
union select 1,17,0,''STRADONE''
union select 1,18,0,''VIA''
union select 1,19,0,''VIALE''
union select 1,20,0,''VICOLO''
union select 1,21,0,''ZONA''
union select 1,22,2,''C.DA''
union select 1,23,3,''C.SO''
union select 1,24,11,''P.ZZA''
union select 1,25,11,''PZZA''
union select 1,26,19,''V.LE''
union select 1,27,0,''PIAZZALE''
union select 1,28,0,''VICO''
union select 1,29,4,''FRAZ.''
union select 1,31,0,''LARGO''
union select 1,32,0,''VILLA''
union select 1,33,31,''L.GO''
union select 1,34,18,''V.''
union select 1,35,6,''LOCALITA''''''
union select 1,36,15,''STD''
union select 1,37,0,''BORGO''
union select 1,38,37,''BGO''
union select 1,39,15,''S.DA''
union select 1,40,11,''P.ZA''
union select 1,41,0,''PIAZZETTA''
union select 1,42,41,''P.TTA''
union select 1,44,0,''TRAVERSA''
union select 1,45,44,''TRAV.''
union select 1,46,18,''VIA.''
-- union select 1,45,0,''C/O''       -- presso
-- union select 1,46,45,''PRESSO''
union select 1,47,3,''C/SO''       -- corso
union select 1,48,0,''LOC.''
union select 1,49,2,''C/DA''
union select 1,50,2,''CONTR.''
union select 1,51,3,''CSO''       -- corso
--union select 1,52,45,''P/O''       -- presso
union select 1,53,0,''DISTRETTO''
union select 1,54,0,''CORTE''
union select 1,55,19,''VLE''
union select 1,56,37,''B.GO''
union select 1,57,11,''P.''
union select 1,58,2,''CDA''
union select 1,59,15,''STR.COMUNALE''
union select 1,60,15,''STR.''
union select 1,61,3,''C.''
union select 1,62,0,''CENTRO DIREZIONALE''
union select 1,63,0,''PARCO''
union select 1,64,0,''GALLERIA''
union select 1,65,63,''PCO''       -- parco
union select 1,66,0,''POLICLINICO''
union select 1,67,0,''FARMACIA COMUNALE''
union select 1,68,0,''FARMACIA''
union select 1,69,67,''FARM.COMUN.''
union select 1,70,0,''CORTILE''
union select 1,71,32,''VILL.''
union select 1,72,48,''LOC''
union select 1,73,3,''C.SO''       -- corso
union select 1,74,0,''BORGATA''
union select 1,75,74,''B.TA''
-- union select 1,76,0,''CASA DI RIPOSO''    -- è un C/O, vedere fn__place_at
union select 1,77,0,''PASSAGGIO PRIVATO''
union select 1,78,15,''ST.''
union select 1,79,15,''STR''
union select 1,80,15,''STRDA''
union select 1,81,7,''L.MARE''
union select 1,82,7,''LG.MARE''
union select 1,83,2,''CONT.DA''
union select 1,84,2,''CON.DA''
union select 1,85,0,''CIRCONVALLAZIONE''
union select 1,86,0,''CENTRO COMMERCIALE''
union select 1,87,86,''CENTRO COMM.LE''
union select 1,88,45,''VICINO''
union select 1,89,0,''SALITA''
union select 1,90,0,''REGIONE''
union select 1,91,0,''CASCINA''
union select 1,94,0,''CENTRO VACANZE''  -- è un C/O, verificare presenza di name
union select 1,95,0,''RUE''   -- paesi di confine francese
-- end fn__place_type'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__place_type:

-- =================================================================== fn__range
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__range',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130808
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__range') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__range') with nowait
        goto skip_fn__range
        end
    if @ver>130808
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__range') with nowait
        goto skip_fn__range
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__range') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__range'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__range]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:130808\s.zaglio: faster but for mssql2k5 or greater
    v:100501\s.zaglio: converted into @table
    v:090614\s.zaglio: return a numerator
    t:select row from fn__range(20,60,1)
    t:select * from fn__range(-20,-10,1)
    t:select row from fn__range(500,50000,1000)
    t:select * from fn__range(500,5000000,1000)
*/
CREATE function [dbo].[fn__range](@from int, @to int,@step int)
returns table
as
return
with a as (select 1 as n union all select 1) -- 2
     ,b as (select 1 as n from a ,a a1)       -- 4
     ,c as (select 1 as n from b ,b b1)       -- 16
     ,d as (select 1 as n from c ,c c1)       -- 256
     ,e as (select 1 as n from d ,d d1)       -- 65,536
     ,f as (select 1 as n from e ,e e1)       -- 4,294,967,296=17+trillion chrs
     ,factored as (select row_number() over (order by n) rn from f)
select (rn-1)*@step+@from as row
from factored
where rn<=(@to/@step-@from/@step+1)
and ((rn-1)*@step+@from)<=@to
-- fn__range'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__range:

-- =============================================================== fn__reg_parse
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__reg_parse',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100919
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__reg_parse') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__reg_parse') with nowait
        goto skip_fn__reg_parse
        end
    if @ver>100919
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__reg_parse') with nowait
        goto skip_fn__reg_parse
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__reg_parse') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__reg_parse'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__reg_parse]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100919\s.zaglio: parse registry name and split into parts
    t:select * from fn__reg_parse(''hklm\key1\key2\val'')
*/
create function fn__reg_parse(@key nvarchar(512))
returns table
as
return
select
    case left(@key,charindex(''\'',@key)-1)
    when ''hklm'' then ''hkey_local_machine''
    when ''hkcu'' then ''hkey_current_user''
    else left(@key,charindex(''\'',@key)-1)
    end as [root],

    substring(@key,charindex(''\'',@key)+1,
              dbo.fn__charindex(''\'',@key,-1)
              -charindex(''\'',@key)-1)
    as [key],

    substring(@key,dbo.fn__charindex(''\'',@key,-1)+1,128)
    as [value]
-- end fn__reg_parse'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__reg_parse:

-- ============================================================== fn__script_col
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__script_col',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120731
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__script_col') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__script_col') with nowait
        goto skip_fn__script_col
        end
    if @ver>120731
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__script_col') with nowait
        goto skip_fn__script_col
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_col') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__script_col'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__script_col]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,script
    v:120731\s.zaglio: list cols info; used by sp__script...
    t:select * from fn__script_col(default) order by tablename,tableowner,columnid
*/
create function fn__script_col(@tbl_id int)
returns table
return
select top 100 percent
         sysobjects.name                                                   as tablename,
         sysusers.name                                                     as tableowner,
         c.name                                                            as columnname,
         c.colid                                                           as columnid,
         st.name                                                           as typename,
         case
           when bt.name in (N''nchar'',N''nvarchar'')
           then c.length / 2
           else c.length
         end as length,
         columnproperty(c.id,c.name,N''precisioN'')                          as [precision],
         columnproperty(c.id,c.name,N''scale'')                              as scale,
         convert(bit,columnproperty(c.id,c.name,N''isidentity''))            as [identity],
         bt.name                                                           as basetypename,
         convert(bit,c.iscomputed)                                         as iscomputed,
         convert(bit,columnproperty(c.id,c.name,N''isidnotforrepl''))        as notforreplication,
         convert(bit,columnproperty(c.id,c.name,N''allowsnull''))            as allownulls,
         case
           when (columnproperty(c.id,c.name,N''isidentity'') <> 0)
           then cast(ident_seed(''['' + sysusers.name + ''].['' + sysobjects.name + '']'') as decimal(38))
           else cast(0 as decimal(38))
         end as identityseed,
         case
           when (columnproperty(c.id,c.name,N''isidentity'') <> 0)
           then ident_incr(''['' + sysusers.name + ''].['' + sysobjects.name + '']'')
           else 0
         end as identityincrement,
         case
           when (objectproperty(c.cdefault,N''isdefaultcnst'') <> 0)
           then null
           else user_name(d.uid) + N''.'' + d.name
         end as defaultname,
         c.cdefault                                                        as defaulttextid,
         user_name(st.uid)                                                 as typeowner,
         user_name(r.uid) + N''.'' + r.name                                  as rulename,
         case
           when (objectproperty(c.cdefault,N''isdefaultcnst'') <> 0)
           then object_name(c.cdefault)
           else null
         end as dridefaultname,
         c.cdefault                                                        as defaultid,
         df.[text]                                                         as dridefaultcode,
         convert(bit,columnproperty(c.id,c.name,N''isfulltextindexed''))     as fulltextindexed,
         cc.text                                                           as computedtext,
         convert(bit,columnproperty(sysobjects.id,c.name,N''isrowguidcol'')) as isrowguidcol,
         c.collation                                                       as collation,
         c.language                                                        as fulltextlanguage,
         ftjoin.name                                                       as fulltexttypecolumn
from     dbo.syscolumns c with (nolock)
         inner join dbo.systypes st
           on st.xusertype = c.xusertype
         inner join dbo.systypes bt with (nolock)
           on bt.xusertype = c.xtype
         inner join dbo.sysobjects with (nolock)
           on sysobjects.id = c.id
         left join dbo.sysusers with (nolock)
           on sysusers.uid = sysobjects.uid
         left join dbo.sysobjects d with (nolock)
           on d.id = c.cdefault
         left join dbo.sysobjects r with (nolock)
           on r.id = c.domain
         left join dbo.syscomments cc with (nolock)
           on cc.id = sysobjects.id
              and cc.number = c.colid
         left join (select ftdep.id,
                           ftdep.number,
                           ftcol2.name
                    from   sysdepends ftdep
                           left join syscolumns ftcol2
                             on ftcol2.colid = ftdep.depnumber
                    where  columnproperty(ftdep.id,ftcol2.name,''istypeforfulltextblob'') = 1
                           and ftdep.id = ftdep.depid
                           and ftdep.id = ftcol2.id) ftjoin
           on ftjoin.id = c.id
              and ftjoin.number = c.colid
              and ftjoin.id = c.id
         left join dbo.syscomments df with (nolock)
           on df.id=c.cdefault
where    objectproperty(c.id,''istable'') = 1
         and objectproperty(c.id,''issystemtable'') = 0
         and (@tbl_id is null or c.id=@tbl_id)
-- end fn__script_col'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__script_col:

-- ============================================================== fn__script_idx
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__script_idx',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121005
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__script_idx') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__script_idx') with nowait
        goto skip_fn__script_idx
        end
    if @ver>121005
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__script_idx') with nowait
        goto skip_fn__script_idx
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_idx') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__script_idx'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__script_idx]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,script
    v:121005\s.zaglio: done previous
    v:121004\s.zaglio: a bug near included columns
    v:120802\s.zaglio: added more column info and index_id
    v:120731\s.zaglio: adapted to mssql 2k5
    v:120305\s.zaglio: list indexes info (used by sp__script..)
    t:select * from fn__script_idx(object_id(''cfg''))
*/
CREATE function fn__script_idx(@tbl_id int=null)
returns table
as
return
select
       sysindexes.id                                                              as [object_id],
       sysindexes.indid                                                           as index_id,
       six.index_column_id                                                        as index_column_id,
       sysindexkeys.keyno                                                         as keyno,
       convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isclustered''))   as [clustered],
       convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isunique''))      as [unique],
       convert(bit,case
                     when (sysindexes.status & 4096) = 0
                     then 0
                     else 1
                   end)                                                           as uniqueconstraint,
       convert(bit,case
                     when (sysindexes.status & 2048) = 0
                     then 0
                     else 1
                   end)                                                           as [primary],
       convert(bit,case
                     when (sysindexes.status & 0x1000000) = 0
                     then 0
                     else 1
                   end)                                                           as norecompute,
       convert(bit,case
                     when (sysindexes.status & 0x1) = 0
                     then 0
                     else 1
                   end)                                                           as ignoredupkey,
       convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''ispadindex''))    as ispadindex,
       convert(bit,objectproperty(sysindexes.id,N''istable''))                      as istable,
       convert(bit,objectproperty(sysindexes.id,N''isview''))                       as isview,
       convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isfulltextkey'')) as fulltextkey,
       convert(bit,indexproperty(sysindexes.id,sysindexes.name,N''isstatistics''))  as [statistics],
       sysfilegroups.groupname                                                    as filegroup,
       sysobjects.name                                                            as parentname,
       sysusers.name                                                              as parentowner,
       sysindexes.name                                                            as indexname,
       sysindexes.origfillfactor                                                  as [fillfactor],
       sysindexes.status,
       syscolumns.name                                                            as columnname,
       syscolumns.xusertype                                                       as columnxusertype,
       systypes.name                                                              as columntype,
       convert(bit,isnull(indexkey_property(syscolumns.id,sysindexkeys.indid,keyno,''isdescending''),
                          0))                                                     as descending,
       isnull(six.is_included_column,0)                                           as is_included_column

from    sysindexes with (nolock)                       -- select * from sysindexes where name=''ix_log_ddl''
        inner join sysindexkeys with (nolock)          -- select * from sysindexkeys where indid=2 and id=2103730597
           on sysindexes.indid = sysindexkeys.indid     -- select * from sys.indexes where name=''ix_log_ddl''
              and sysindexkeys.id = sysindexes.id       -- select * from sys.indexkeys where indid=2 and id=2103730597
        inner join syscolumns with (nolock)            -- select * from syscolumns where id=2103730597 and colid in (1,6,12,4)
           on syscolumns.colid = sysindexkeys.colid     -- select * from sys.index_columns where object_id=2103730597 and index_id=2
              and syscolumns.id = sysindexes.id
        inner join sysobjects with (nolock)
           on sysobjects.id = sysindexes.id
        left join sysusers with (nolock)
           on sysusers.uid = sysobjects.uid
        left join sysfilegroups with (nolock)
           on sysfilegroups.groupid = sysindexes.groupid
        join sys.index_columns six
            on sysindexes.id  = six.[object_id]
            and sysindexes.indid  = six.[index_id]
            and sysindexkeys.keyno = six.key_ordinal
            and sysindexkeys.colid = six.column_id
            -- and six.is_included_column=1
        join systypes
            on syscolumns.xusertype=systypes.xusertype
where    (objectproperty(sysindexes.id,''istable'') = 1
           or objectproperty(sysindexes.id,''isview'') = 1)
         and objectproperty(sysindexes.id,''issystemtable'') = 0
         and indexproperty(sysindexes.id,sysindexes.name,N''isautostatistics'') = 0
         and indexproperty(sysindexes.id,sysindexes.name,N''ishypothetical'') = 0
         and sysindexes.name is not null
         and (@tbl_id is null or sysobjects.id=@tbl_id)
-- fn__script_idx'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__script_idx:

-- ============================================================== fn__script_tbl
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__script_tbl',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120731
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__script_tbl') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__script_tbl') with nowait
        goto skip_fn__script_tbl
        end
    if @ver>120731
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__script_tbl') with nowait
        goto skip_fn__script_tbl
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_tbl') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__script_tbl'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__script_tbl]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,script
    v:120731\s.zaglio: list tbls info; used by sp__script...
    t:select * from fn__script_tbl(default)
*/
CREATE function fn__script_tbl(@tbl_id int)
returns table
return
select
       o.name,
       user_name(o.uid)                                                as owner,
       o.id,
       convert(bit,objectproperty(o.id,''tablehasactivefulltextindex'')) as fulltextindexed,
       sysfulltextcatalogs.name                                        as fulltextcatalogname,
       sysfilegroups.groupname                                         as filegroup,
       (select top 1 groupname
        from   sysfilegroups
               inner join sysindexes
                 on sysindexes.groupid = sysfilegroups.groupid
        where  sysindexes.indid = 255
               and sysindexes.id = o.id)                               as textfilegroup
from     dbo.sysobjects o with (nolock)
         left join sysfulltextcatalogs with (nolock)
           on sysfulltextcatalogs.ftcatid = o.ftcatid
         left join sysindexes with (nolock)
           on sysindexes.id = o.id
         left join sysfilegroups with (nolock)
           on sysfilegroups.groupid = sysindexes.groupid
where    objectproperty(o.id,N''istable'') = 1
         and objectproperty(o.id,N''ismsshipped'') = 0
         and objectproperty(o.id,N''issystemtable'') = 0
         and objectproperty(o.id,N''tableisfake'') = 0
         and sysindexes.indid < 2
         and (@tbl_id is null or o.id=@tbl_id)
-- end fn__script_tbl'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__script_tbl:

-- ============================================================== fn__script_trg
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__script_trg',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120731
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__script_trg') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__script_trg') with nowait
        goto skip_fn__script_trg
        end
    if @ver>120731
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__script_trg') with nowait
        goto skip_fn__script_trg
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_trg') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__script_trg'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__script_trg]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,script
    v:120731\s.zaglio: list cols info; used by sp__script...
    t:select * from fn__script_trg(default) order by tablename,tableowner,columnid
*/
create function fn__script_trg(@tbl_id int)
returns table
return
select
       sysobjects.id,
       sysobjects.name                                                       as triggername,
       u2.name                                                               as triggerowner,
       t.name                                                                as parentname,
       t.id                                                                  as parentid,
       sysusers.name                                                         as parentowner,
       convert(bit,objectproperty(sysobjects.id,''execisupdatetrigger''))      as isupdatetrigger,
       convert(bit,objectproperty(sysobjects.id,''execisdeletetrigger''))      as isdeletetrigger,
       convert(bit,objectproperty(sysobjects.id,''execisinserttrigger''))      as isinserttrigger,
       convert(bit,objectproperty(sysobjects.id,''execisaftertrigger''))       as isaftertrigger,
       convert(bit,objectproperty(sysobjects.id,''execisinsteadoftrigger''))   as isinsteadoftrigger,
       convert(bit,objectproperty(sysobjects.id,''execisquotedidentoN''))      as quotedidentifier,
       convert(bit,objectproperty(sysobjects.id,''execisansinullsoN''))        as ansinulls,
       convert(bit,objectproperty(sysobjects.id,''execisfirstdeletetrigger'')) as execisfirstdeletetrigger,
       convert(bit,objectproperty(sysobjects.id,''execisfirstinserttrigger'')) as execisfirstinserttrigger,
       convert(bit,objectproperty(sysobjects.id,''execisfirstupdatetrigger'')) as execisfirstupdatetrigger,
       convert(bit,objectproperty(sysobjects.id,''execislastdeletetrigger''))  as execislastdeletetrigger,
       convert(bit,objectproperty(sysobjects.id,''execislastinserttrigger''))  as execislastinserttrigger,
       convert(bit,objectproperty(sysobjects.id,''execislastupdatetrigger''))  as execislastupdatetrigger,
       convert(bit,objectproperty(sysobjects.id,''execistriggerdisabled''))    as isdisabled,
       convert(bit,objectproperty(t.id,''istable''))                           as istable,
       convert(bit,objectproperty(t.id,''isview''))                            as isview,
       syscomments.encrypted                                                 as encrypted
from     sysobjects with (nolock)
         inner join sysobjects t with (nolock)
           on t.id = sysobjects.parent_obj
         left join sysusers with (nolock)
           on sysusers.uid = t.uid
         left join sysusers u2 with (nolock)
           on u2.uid = sysobjects.uid
         left join syscomments with (nolock)
           on sysobjects.id = syscomments.id
where    sysobjects.type = ''tr''
         and isnull(syscomments.colid,1) = 1
         and (@tbl_id is null or sysobjects.parent_obj=@tbl_id)
-- end fn__script_trg'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__script_trg:

-- ============================================================= fn__server_info
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__server_info',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130517
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__server_info') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__server_info') with nowait
        goto skip_fn__server_info
        end
    if @ver>130517
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__server_info') with nowait
        goto skip_fn__server_info
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__server_info') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__server_info'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__server_info]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    d:130517\s.zaglio:sp__clientip
    d:130517\s.zaglio:sp__serverip
    d:130517\s.zaglio:sp__parse_conn
    v:130517\s.zaglio:return info about this server, changed from txt to tbl
    v:081003\s.zaglio:old version
    t:select * from fn__server_info()
*/
CREATE function fn__server_info()
returns table
as
return
select
    coalesce(convert(sysname,serverproperty(''machinename'')),'''') as machine_name,
    coalesce(convert(sysname,serverproperty(''servername'') ),'''') as server_name,
    local_net_address as server_ip,
    coalesce(convert(sysname,serverproperty(''instancename'')),'''') as instance_name,
    local_tcp_port as instance_port,
    coalesce(convert(sysname,serverproperty(''edition'') ),'''') as edition,
    coalesce(convert(sysname,serverproperty(''productversion'') ),'''') as product_version,
    coalesce(convert(sysname,serverproperty(''productlevel'') ),'''') as product_level,
    coalesce(convert(sysname,serverproperty(''engineedition'')),'''') as engine_edition,
    coalesce(convert(sysname,serverproperty(''computernamephysicalnetbios'')),'''') as computer_name_physical_netbios

-- select *
from sys.dm_exec_connections
where session_id=@@spid
-- fn__server_info'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__server_info:

-- ======================================================= fn__sessionproperties
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__sessionproperties',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110126
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__sessionproperties') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__sessionproperties') with nowait
        goto skip_fn__sessionproperties
        end
    if @ver>110126
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__sessionproperties') with nowait
        goto skip_fn__sessionproperties
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__sessionproperties') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__sessionproperties'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__sessionproperties]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110126\s.zaglio: return all session properties
    t:select * from fn__sessionproperties()
*/
create function fn__sessionproperties()
returns table
as
return
select SESSIONPROPERTY(''ANSI_NULLS'') VALUE,''ANSI_NULLS'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''ANSI_PADDING'') VALUE,''ANSI_PADDING'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''ANSI_WARNINGS'') VALUE,''ANSI_WARNINGS'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''ARITHABORT'') VALUE,''ARITHABORT'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''CONCAT_NULL_YIELDS_NULL'') VALUE,''CONCAT_NULL_YIELDS_NULL'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''NUMERIC_ROUNDABORT'') VALUE,''NUMERIC_ROUNDABORT'' as SESSIONPROPERTY
union
select SESSIONPROPERTY(''QUOTED_IDENTIFIER'') VALUE,''QUOTED_IDENTIFIER'' as SESSIONPROPERTY'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__sessionproperties:

-- ============================================================== fn__str_params
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_params',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130909
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_params') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_params') with nowait
        goto skip_fn__str_params
        end
    if @ver>130909
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_params') with nowait
        goto skip_fn__str_params
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_params') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_params'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_params]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:130909\s.zaglio: optimized using with
    v:111114\s.zaglio: optimized and added to grp util_tkns
    v:100718\s.zaglio: same as fn__str_table but reduce tokens
    t:
        select * from dbo.fn__str_params(''a,b  ,c,
                                         d,  e  ,  f'','','',default)
*/
CREATE function [dbo].[fn__str_params](
    @data nvarchar (4000),
    @sep nvarchar (32)=''|'',
    @reserved bit=null
    )
returns table
as
return
-- declare @data sysname,@sep sysname
-- select @data='' a b c '',@sep='' '';
with pieces(pos, start, [stop]) as (
  select 1, 1, charindex(@sep, @data)
  union all
  select
    pos + 1,
    [stop] + (datalength(@sep)/2),
    charindex(@sep, @data, [stop] + (datalength(@sep)/2))
  from pieces
  where [stop] > 0
)
select pos,
    token=ltrim(rtrim(replace(replace(replace(
            substring(@data, start,
                      case when [stop] > 0 then [stop]-start else 4000 end
                     ),
            cr,''''),lf,''''),tab,'''')))
from pieces,fn__sym()
-- fn__str_table_fast'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_params:

-- =============================================================== fn__str_split
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_split',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130909
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_split') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_split') with nowait
        goto skip_fn__str_split
        end
    if @ver>130909
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_split') with nowait
        goto skip_fn__str_split
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_split') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_split'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_split]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:%licence%
    g:utility
    o:130909\s.zaglio: fn__str_table_fast
    c:http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings
    c:option (maxrecursion 0)
    v:130909\s.zaglio: unified fn__str_split and fn__str_table_fast
    v:120909\s.zaglio: faster version of fn__str_table for few lines
    t:select * from dbo.fn__str_split(''a|b|c'',''|'')
    t:select * from dbo.fn__str_split(''a\n\nc'',''\n'') <-- is correct have only one line empty
    t:select * from dbo.fn__str_split(null,'';'')
    t:select * from dbo.fn__str_split(''a;b;c'',null) -- a;b;c
    t:select * from dbo.fn__str_split(''one two tree four  test'','''')
    t:select * from dbo.fn__str_split(''one, two, tree,'','','')
    t:
        select l,s.* from (
            select ''1|a|aa'' as l union
            select ''2|b|bb'' as l union
            select ''3|c|cc'' as l union
            select ''4|d|dd'' as l
        ) as data
        cross apply dbo.fn__str_table_fast(data.l,''|'') s
    t:select * from fn__Str_table(''a b c'','''')
    t:select * from fn__Str_table_fast(''a b c'','''')
*/
CREATE function [dbo].[fn__str_split](
  @data nvarchar (4000),
  @sep nvarchar (32)=''|''
  )
returns table
as
return
-- declare @data sysname,@sep sysname
-- select @data='' a b c '',@sep='' '';
with pieces(pos, start, [stop]) as (
  select
    1, 1,
    charindex(case @sep when '''' then '' '' else @sep end, @data)
  union all
  select
    pos + 1, [stop] + (datalength(sep)/2),
    charindex(sep, @data, [stop] + (datalength(sep)/2))
  from pieces,
       (select case @sep when '''' then '' '' else @sep end sep) sep
  where [stop] > 0
)
select pos,
  substring(@data, start,
            case when [stop] > 0 then [stop]-start else 4000 end
            ) as token
  -- ,len(sep) ns
from pieces
-- fn__str_table_fast'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_split:

-- ========================================================== fn__str_table_fast
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_table_fast',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130909
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_table_fast') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_table_fast') with nowait
        goto skip_fn__str_table_fast
        end
    if @ver>130909
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_table_fast') with nowait
        goto skip_fn__str_table_fast
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_table_fast') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_table_fast'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_table_fast]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:%licence%
    g:utility
    a:130909\s.zaglio: fn__str_split
    v:130909\s.zaglio: unified fn__str_split and fn__str_table_fast
    v:120909\s.zaglio: faster version of fn__str_table for few lines
    t:select * from dbo.fn__str_split(''a|b|c'',''|'')
    t:select * from dbo.fn__str_split(''a\n\nc'',''\n'') <-- is correct have only one line empty
    t:select * from dbo.fn__str_split(null,'';'')
    t:select * from dbo.fn__str_split(''a;b;c'',null) -- a;b;c
    t:select * from dbo.fn__str_split(''one two tree four  test'','''')
    t:select * from dbo.fn__str_split(''one, two, tree,'','','')
    t:
        select l,s.* from (
            select ''1|a|aa'' as l union
            select ''2|b|bb'' as l union
            select ''3|c|cc'' as l union
            select ''4|d|dd'' as l
        ) as data
        cross apply dbo.fn__str_table_fast(data.l,''|'') s
    t:select * from fn__Str_table(''a b c'','''')
    t:select * from fn__Str_table_fast(''a b c'','''')
*/
CREATE function [dbo].[fn__str_table_fast](
  @data nvarchar (4000),
  @sep nvarchar (32)=''|''
  )
returns table
as
return
-- declare @data sysname,@sep sysname
-- select @data='' a b c '',@sep='' '';
with pieces(pos, start, [stop]) as (
  select
    1, 1,
    charindex(case @sep when '''' then '' '' else @sep end, @data)
  union all
  select
    pos + 1, [stop] + (datalength(sep)/2),
    charindex(sep, @data, [stop] + (datalength(sep)/2))
  from pieces,
       (select case @sep when '''' then '' '' else @sep end sep) sep
  where [stop] > 0
)
select pos,
  substring(@data, start,
            case when [stop] > 0 then [stop]-start else 4000 end
            ) as token
  -- ,len(sep) ns
from pieces
-- fn__str_table_fast'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_table_fast:

-- =========================================================== fn__comment_types
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__comment_types',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100612
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__comment_types') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__comment_types') with nowait
        goto skip_fn__comment_types
        end
    if @ver>100612
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__comment_types') with nowait
        goto skip_fn__comment_types
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__comment_types') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__comment_types'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__comment_types]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100612\s.zaglio: managed unknown objs (retur nothing)
    v:100328\s.zaglio: support for fn__comment,sp__comment
    todo: using MS original methos is slow. Need to be rewritten
    t:
        select * from dbo.fn__comment_types(''sp__comment'')
        select * from dbo.fn__comment_types(''sp__comment.@path'')
        select * from dbo.fn__comment_types(''fn__comment.@path'')
*/
CREATE function [dbo].[fn__comment_types] (
    @path sysname=null
    )
returns @t table (
    prop sysname,
    sch sysname,sch_type sysname,
    obj sysname,obj_type sysname,
    sub sysname null,sub_type sysname null,
    xtype nvarchar(2),id int
    )
as
begin

declare
    @sch sysname,@sch_type sysname,
    @obj sysname,@obj_type sysname,
    @sub sysname,@sub_type sysname,
    @id int,@prop sysname,@xtype nvarchar(2)

if @path is null return

/*
Table 1. Extended property hierarchy for SQL Server 2000.
------------------------------------------------------------------------
Level 0                 Level 1                 Level 2
User                    Table                   Column, index, constraint, trigger
User                    View                    Column, INSTEAD OF trigger
User                    Schema-bound view       Column, index, INSTEAD OF trigger
User                    Procedure               Parameter
User                    Rule                    (none)
User                    Default                 (none)
User                    Function                Column, parameter, constraint
User                    Schema-bound function   Column, parameter, constraint
User-defined datatype   (none)                  (none)
*/

select @prop=N''MS_Description'',
       @sch_type=''Schema''  -- maybe in mssql2k must use ''user''

if charindex(''.'',@path)=0
    select
        @obj=parsename(@path,1)
else
    select
        @sch=parsename(@path,3),
        @obj=parsename(@path,2),
        @sub=parsename(@path,1)

if @sch is null select @sch=[name] from dbo.fn__schema_of(@obj)

select @id=object_id(@sch+''.''+@obj)
if @id is null return

select @xtype=xtype from sysobjects where id=@id

if @xtype in (''V'') select  @obj_type=''View'',     @sub_type=''Column''
if @xtype in (''U'') select  @obj_type=''Table'',    @sub_type=''Column''
if @xtype in (''P'',''TR'') select  @obj_type=''Procedure'',@sub_type=''Parameter''
if @xtype in (''FN'',''IF'',''TF'',''IT'') select  @obj_type=''Function'',@sub_type=''Parameter''
-- select distinct xtype from sysobjects

if charindex(''.'',@path)=0 select @sub_type=null

insert @t select @prop,
                 @sch,@sch_type,@obj,@obj_type,
                 @sub,@sub_type,@xtype,@id
return
end -- fn__comment_types'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__comment_types:

-- ================================================================ fn__comments
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__comments',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100919
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__comments') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__comments') with nowait
        goto skip_fn__comments
        end
    if @ver>100919
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__comments') with nowait
        goto skip_fn__comments
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__comments') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__comments'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__comments]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100919\s.zaglio: compilable in mssql2k but not executable
    v:100228\s.zaglio: added obj_id and null on @table
    v:100204\s.zaglio: return comment of obj
    t:
        create table test_info
            (
            a nchar(10) null,
            b nchar(10) null
            )  on [primary]
        exec sp__comment ''test_info'',''table comment''
        execute sp_addextendedproperty
            N''ms_description'', N''description col a'',
            N''schema'', N''dbo'', N''table'', N''test_info'', N''column'', N''a''

        select * from dbo.fn__comments(''test_info'')

        drop table test_info
*/
CREATE function [dbo].[fn__comments](@table sysname)
returns @t table(obj_id int,column_name sysname null,value nvarchar(4000) null)
as
begin
declare @id int select @id=object_id(@table)
-- select top 10 * from syscolumns
if dbo.fn__isMSSQL2K()=1
    insert @t(obj_id,column_name,value)
    select id,col,com from (
        select      o.id id,
                    o.name as col,
                    convert(nvarchar(4000),p.value) as com,
                    0 as ord
        from    sysobjects o
        join    sysproperties p
                    on o.id = p.id
                    and 0 = p.smallid
        where       p.name=''MS_Description''
        and         @table is null or o.id=@id

        union

        select      o.id id,
                    c.name as col,
                    convert(nvarchar(4000),p.value) as com,
                    c.colorder as ord
        from    sysobjects o
        join    sysproperties p
                    on o.id = p.id
        join    syscolumns c
                    on p.smallid = c.colid
                    and p.id = c.id
        where       p.name=''MS_Description''
        and         @table is null or o.id=@id
    ) qry
    order by ord
else
    insert @t
    select id,col,com from (
        select      o.object_id id, null as col,
                    convert(nvarchar(4000),ep.value) as com,
                    0 as ord
        from        sys.objects o
        join        sys.extended_properties ep
                    on o.object_id = ep.major_id and 0=ep.minor_id
        join        sys.schemas s
                    on o.schema_id = s.schema_id
        where       ep.name=''MS_Description''
        and         @table is null or o.object_id=@id

        union

        select      o.object_id id, c.name as col,
                    convert(nvarchar(4000),ep.value) as com,
                    c.colorder as ord
        from        sys.objects o
        join        sys.extended_properties ep
                    on o.object_id = ep.major_id
        join        sys.schemas s
                    on o.schema_id = s.schema_id
        join        syscolumns c
                    on ep.minor_id = c.colid
                    and ep.major_id = c.id
        where       ep.name=''MS_Description''
        and         @table is null or o.object_id=@id
    ) qry
    order by ord
return
/*
SQLSERVER 2000:

SELECT    sysobjects.Name AS ObjectName,
            sysobjects.xtype AS ObjectType,
            user_name(sysobjects.uid) AS SchemaOwner,
            sysproperties.name AS PropertyName,
            sysproperties.value AS PropertyValue,
            syscolumns.name AS ColumnName,
            syscolumns.colid AS Ordinal
FROM    sysobjects INNER JOIN sysproperties
            ON sysobjects.id = sysproperties.id
            LEFT JOIN syscolumns
            ON sysproperties.smallid = syscolumns.colid
            AND sysproperties.id = syscolumns.id
ORDER BY SchemaOwner, ObjectName, ObjectType, Ordinal

SQLSERVER 2005:
SELECT        o.Name AS ObjectName,
            o.type AS ObjectType,
            s.name AS SchemaOwner,
            ep.name AS PropertyName,
            ep.value AS PropertyValue,
            c.name AS ColumnName,
            c.colid AS Ordinal
FROM        sys.objects o INNER JOIN sys.extended_properties ep
            ON o.object_id = ep.major_id
            INNER JOIN sys.schemas s
            ON o.schema_id = s.schema_id
            LEFT JOIN syscolumns c
            ON ep.minor_id = c.colid
            AND ep.major_id = c.id
WHERE        o.type IN (''V'', ''U'', ''P'')
ORDER BY    SchemaOwner,ObjectName, ObjectType, Ordinal
*/
end -- function'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__comments:

-- ===================================================================== fn__dir
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__dir',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131015
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__dir') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__dir') with nowait
        goto skip_fn__dir
        end
    if @ver>131015
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__dir') with nowait
        goto skip_fn__dir
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__dir') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__dir'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__dir]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:sub,folder,directory,list,sub,folder,s,sp__dir,unicode
    c:from https://www.simple-talk.com/iwritefor/articlefiles/634-dboDIR.htm
    v:131015\s.zaglio: done, but abbandoned because 6-20 times slower than sp
    r:131014\s.zaglio: list content of path and sub paths
    t:select * from fn__dir(''I:\i_do_not_exists'',default) -- raiserror
    t:select * from fn__dir(''I:\temp\'',default)
    t:select * from fn__dir(''I:\temp'',''s'')
    t:select * from fn__dir(''I:\temp'',''s|kp'')
*/
CREATE function [dbo].[fn__dir](@wildcard nvarchar(4000),@opt sysname)
returns @dir table
(
    id int identity primary key,
    rid int,                -- for subdirs
    [flags] smallint,       -- if &32=32 is a ;16 is a error
    [key] nvarchar(446),    -- obj name or error string
    dt datetime,            -- creation date
    n bigint null           -- size in bytes
)
as
-- body of the function
begin
declare
    --all the objects used
    @objshellapplication int,
    @objfolder int,
    @objitem int,
    @objerrorobject int,
    @objfolderitems int,
    --potential error message shows where error occurred.
    @strerrormessage nvarchar(1000),
    --command sent to ole automation
    @command nvarchar(1000),
    @hr int,                            --ole result (0 if ok)
    @count int,@i int,
    @name nvarchar(2000),               --the name of the current item
    @path nvarchar(2000),
    @type nvarchar(2000),
    @modifydate datetime,               --the date the current item last modified
    @isfilesystem int,                  --1 if the current item is part of the file system
    @isfolder int,                      --1 if the current item is a file
    @size bigint,
    @rid int,
    @lp int,                            --len path

    -- options
    @s bit,                             --scan subdirectory
    @kp bit                             --keep root path

if len(coalesce(@wildcard,''''))<2 return

if not @opt is null
    begin
    select @name=''|''+@opt+''|''           --to not |||grow||| in recursion
    select @s=charindex(''|s|'',@name),@kp=charindex(''|kp|'',@name)
    end
else
    select @kp=0,@s=0

if right(@wildcard,1)=''\'' select @wildcard=left(@wildcard,len(@wildcard)-1)

if @kp=0 select @path=@wildcard+''\'',@lp=len(@path)

select @strerrormessage = ''opening the shell application object''
select @objshellapplication=0
exec @hr = sp_oacreate ''shell.application'', @objshellapplication out
if @hr!=0 goto dispose

--now we get the folder.
select  @objerrorobject = @objshellapplication,
       @strerrormessage = ''getting folder"'' + @wildcard + ''"'',
       @command = ''namespace("''+@wildcard+''")''

select @objfolder=0
exec @hr = sp_oamethod @objshellapplication, @command, @objfolder out
if @objfolder is null
    begin
    exec sp_oadestroy @objshellapplication
    return --nothing there. sod the error message
    end

--and then the number of objects in the folder
select  @objerrorobject = @objfolder,
       @strerrormessage = ''getting count of folder items in "''+@wildcard+''"'',
       @command = ''items.count''
exec @hr = sp_oamethod @objfolder, @command, @count out
--now get the folderitems collection
select  @objerrorobject = @objfolder,
        @strerrormessage = '' getting folderitems'',
       @command=''items()''
exec @hr = sp_oamethod @objfolder, @command, @objfolderitems output

select @i = 0, @rid = 0

--iterate through the folderitems collection
--http://msdn.microsoft.com/en-us/library/windows/desktop/bb787810(v=vs.85).aspx
while @hr=0 and @i<@count
    begin
    select @objerrorobject = @objfolderitems,
           @strerrormessage = '' getting folder item ''+cast(@i as varchar(5)),
           @command=''item('' + cast(@i as varchar(5))+'')''
           --@command=''getdetailsof(''+ cast(@i as varchar(5))+'',1)''
    exec @hr = sp_oamethod @objfolderitems, @command, @objitem output
    select  @objerrorobject = @objitem,
            @strerrormessage = '' getting folder item properties''
                   + cast(@i as varchar(5))

    exec @hr = sp_oamethod @objitem,''path'', @name output
    if @hr!=0 break
    if @kp=0 select @name=stuff(@name,1,@lp,'''')

    exec @hr = sp_oamethod @objitem,''type'', @type output
    if @hr!=0 break

    exec @hr = sp_oamethod @objitem,''modifydate'', @modifydate output
    if @hr!=0 break

    exec @hr = sp_oamethod @objitem,''size'', @size output
    if @hr!=0 break
    /*
    exec @hr = sp_oamethod @objitem,''isfilesystem'', @isfilesystem output
    if @hr!=0 break
    */
    exec @hr = sp_oamethod @objitem,''isfolder'', @isfolder output
    if @hr!=0 break

    --and insert the properties into a table
    insert into @dir (rid, flags, [key], dt, n)
    select
        @rid,
        case @isFolder when 1 then 32 else 0 end,
        @name,
        @modifydate,
        @size

    exec sp_oadestroy @objitem
    select @objitem=0

    select @i=@i+1
    end -- files loop

dispose:

if @hr <> 0
    begin
    declare
        @source nvarchar(255),
        @description nvarchar(255),
        @helpfile nvarchar(255),
        @helpid int

    exec sp_oageterrorinfo @objerrorobject, @source output,
        @description output, @helpfile output, @helpid output
    select  @strerrormessage = ''error whilst ''
            + coalesce(@strerrormessage, ''doing something'') + '', ''
            + coalesce(@description, '''')
    -- insert into @dir(flags,[key]) select 16,left(@strerrormessage,2000)
    end

if @objitem!=0 exec sp_oadestroy @objitem
if @objfolder!=0 exec sp_oadestroy @objfolder
if @objshellapplication!=0 exec sp_oadestroy @objshellapplication

-- raiserror
if @hr!=0 select @i=cast(left(@strerrormessage,2000) as int)

-- ============================================================== sub folders ==
if @s=0 return

declare cs cursor local for
    select id,case @kp when 0 then @path+[key] else [key] end
    from @dir
    where rid=@rid and flags&32=32
open cs
while 1=1
    begin
    fetch next from cs into @rid,@name
    if @@fetch_status!=0 break

    insert into @dir (rid, flags, [key], dt, n)
    select @rid,flags,[key],dt,n
    from fn__dir(@name,@opt)

    end -- cursor cs
close cs
deallocate cs

return
end -- fn__dir'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__dir:

-- ========================================================== fn__dir_parse_list
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__dir_parse_list',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=140110
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__dir_parse_list') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__dir_parse_list') with nowait
        goto skip_fn__dir_parse_list
        end
    if @ver>140110
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__dir_parse_list') with nowait
        goto skip_fn__dir_parse_list
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__dir_parse_list') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__dir_parse_list'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__dir_parse_list]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:dir,list,command,parse,name,date,size,directory
    v:140110\s.zaglio: bug near eng dt (solved but maybe not completelly)
    v:131016.1030\s.zaglio: support and simplify sp__dir
    t:sp__dir ''%temp%\*.*'',@dbg=2
*/
CREATE function fn__dir_parse_list(@line nvarchar(4000),@opt sysname)
returns @t table(
    sdt sysname,
    sfsize sysname null,
    name nvarchar(446)
)
as
begin
declare @max_file_name_size int select @max_file_name_size=446
if @opt=''I''
    --         10        20        30        40        50        60        70        80
    -- 123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.
    -- 14/09/2010  15.34         1.106.500 FILENAME
    -- 25/01/2010  12.27              ADFS
    -- select convert(datetime,''09/01/14 03:30:00PM'')
insert @t(sdt,sfsize,name)
    select
        substring(@line,7,4)+''-''+substring(@line,4,2)+''-''+substring(@line,1,2)
                        +''T''
                        +substring(@line,13,2)+'':''+substring(@line,16,2)+'':00.000''
        as sat,
        ltrim(rtrim(replace(replace(substring(@line,20,16),''.'',''''),'','','''')))
        as sfsize,
        substring(@line,37,@max_file_name_size) [key]

else if @opt=''E''

    --         10        20        30        40        50        60        70        80
    -- 123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.
    -- 10/06/2011  04:39 PM              1040
    -- 12/31/2013  02:00 AM               137 tmp_3A2D662D_C46C_425F_8EBA_91635D98C83B
    -- set language english
    -- set language italian
    -- Hijri: dd/mm/yyyy hh:mi:ss:mmmAM: this return a bad year
    -- select convert(sysname,convert(datetime,''04:43:00PM''),8)
    -- xp_cmdshell ''dir %temp%\*.*''
    -- select convert(datetime,''12/24/13 04:43:00PM'')
    insert @t(sdt,sfsize,name)
    select
        /* substring(@line,4,2)+''/''+substring(@line,1,2)+''/''+substring(@line,9,2)
        +'' ''
        +convert(sysname,
                 convert(datetime,
                         substring(@line,13,2)+'':''+
                         substring(@line,16,2)+'':00''+
                         substring(@line,19,2)
                         )
                )
        */
        substring(@line,1,20)   -- 140110\s.zaglio
        as sdt, -- gg/mm/aa hh:mi:ss:mmmAM
        ltrim(rtrim(replace(replace(substring(@line,21,18),''.'',''''),'','',''''))) sfsize,
        substring(@line,40,@max_file_name_size) [key]

return
end -- fn__dir_parse_list'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__dir_parse_list:

-- =========================================================== fn__file_property
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__file_property',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100212
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__file_property') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__file_property') with nowait
        goto skip_fn__file_property
        end
    if @ver>100212
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__file_property') with nowait
        goto skip_fn__file_property
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__file_property') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__file_property'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__file_property]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100212\s.zaglio: return file info
    c:from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=99653
    t:select * from fn__file_property(''c:\boot.ini'')
*/
create function fn__file_property(
    @filename nvarchar (1024)
)
returns @results table (
    errorcode tinyint default (0),
    propname nvarchar (255),
    propvalue sql_variant)
as
begin
declare @oleresult int
declare @fs int
declare @fileid int
declare @message nvarchar (4000)
declare @errorsource nvarchar (255)
declare @errordesc nvarchar (255)
declare @int int
declare @nvarchar nvarchar (1024)
declare @datetime datetime
declare @bigint bigint

-- create an instance of the file system object
execute @oleresult = sp_oacreate ''scripting.filesystemobject'', @fs out
if @oleresult <> 0
begin
exec sp_oageterrorinfo @fs, @errorsource out, @errordesc out

insert @results (errorcode, propname, propvalue)
values (1, @errorsource, @errordesc)

return
end

exec @oleresult = sp_oamethod @fs, ''getfile'', @fileid out, @filename
if @oleresult <> 0
begin
exec sp_oageterrorinfo @fs, @errorsource out, @errordesc out

insert @results (errorcode, propname, propvalue)
values (1, @errorsource, @errordesc)

return
end

exec @oleresult = sp_oagetproperty @fileid, ''attributes'', @int out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''attributes'', '''')
end
else
insert @results (propname, propvalue)
values (''attributes'', @int)

exec @oleresult = sp_oagetproperty @fileid, ''datecreated'', @datetime out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''datecreated'', '''')
end
else
insert @results (propname, propvalue)
values (''datecreated'', @datetime)

exec @oleresult = sp_oagetproperty @fileid, ''datelastaccessed'', @datetime out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''datelastaccessed'', '''')
end
else
insert @results (propname, propvalue)
values (''datelastaccessed'', @datetime)

exec @oleresult = sp_oagetproperty @fileid, ''datelastmodified'', @datetime out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''datelastmodified'', '''')
end
else
insert @results (propname, propvalue)
values (''datelastmodified'', @datetime)

exec @oleresult = sp_oagetproperty @fileid, ''name'', @nvarchar out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''name'', '''')
end
else
insert @results (propname, propvalue)
values (''name'', @nvarchar)

exec @oleresult = sp_oagetproperty @fileid, ''path'', @nvarchar out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''path'', '''')
end
else
insert @results (propname, propvalue)
values (''path'', @nvarchar)

exec @oleresult = sp_oagetproperty @fileid, ''shortpath'', @nvarchar out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''shortpath'', '''')
end
else
insert @results (propname, propvalue)
values (''shortpath'', @nvarchar)

exec @oleresult = sp_oagetproperty @fileid, ''size'', @bigint out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''size'', '''')
end
else
insert @results (propname, propvalue)
values (''size'', @bigint)

exec @oleresult = sp_oagetproperty @fileid, ''type'', @nvarchar out
if @oleresult <> 0
begin
insert @results (errorcode, propname, propvalue)
values (1, ''type'', '''')
end
else
insert @results (propname, propvalue)
values (''type'', @nvarchar)

execute @oleresult = sp_oadestroy @fileid
execute @oleresult = sp_oadestroy @fs

return
end -- function'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__file_property:

-- ========================================================== fn__ftp_parse_list
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__ftp_parse_list',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130603
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__ftp_parse_list') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__ftp_parse_list') with nowait
        goto skip_fn__ftp_parse_list
        end
    if @ver>130603
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__ftp_parse_list') with nowait
        goto skip_fn__ftp_parse_list
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__ftp_parse_list') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__ftp_parse_list'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__ftp_parse_list]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:ftp,list,command,parse,name,date,size,directory,dir,x
    v:130603\s.zaglio: added microsoft and winscp style
    v:130531\s.zaglio: parse line of ls/dir command
    t:
        set language english -- for jan, ...
        select convert(datetime,[timestamp],100) dt,*
        from (
            select ''-- test'' as line
            union select
                ''-rw-r--r--   1 1003     1004       1834147 Apr 20 14:13:06 2012 file''
            union select
                ''05-29-12  03:46PM                  652 file''
            union select
                ''03-26-07  03:16AM                 directory''
            union select
                ''-rw-r--r-- 1 ftp ftp           3613 Jan 03  2012 file''
            union select
                ''-rw-r--r--    1 23208    3600        22588 Jan 11 1:43 file''
            union select
                -- probable IBM
                -- Volume Unit     Date  Ext Used Recfm Lrecl BlkSz Dsorg Dsname
                ''APCSPL 3380D  07/16/97  1    1  FB      80  8800  PS  ETC.RPC''
            ) a
        cross apply fn__ftp_parse_list(1,line,default)
*/
CREATE function fn__ftp_parse_list(@lno int,@line nvarchar(4000),@opt sysname)
returns @t table(
    lno int null,
    dir char(1) null,
    [permissions] char(9) null,
    filecode sysname null,
    [owner] sysname null,
    [group] sysname null,
    size int null,
    [timestamp] sysname null,   -- returned as type 100
    name sysname
)
as
begin
/*
^
(?[\-ld])
(?([\-r][\-w][\-xs]){3})
\s+
(?\d+)
\s+
(?\w+)
\s+
(?\w+)
\s+
(?\d+)
\s+
(?
 ((?\w{3})\s+(?\d{2})\s+(?\d{1,2}):(?\d{2}))
 |
 ((?\w{3})\s+(?\d{2})\s+(?\d{4}))
)
\s+
(?.+)
$
*/
declare
    @s1 int,@s2 int,@s3 int,@s4 int,@s5 int,
    @dts sysname,@tmp sysname,
    @dir char(1),@group sysname,@owner sysname,@size sysname,@name sysname,
    @permissions char(9),@filecode char(1), @done bit

-- strip spaces and mark words positions
select @done=0,@line=ltrim(@line)
while charindex(''  '',@line)>0 select @line=replace(@line,''  '','' '')

select
    @s1=charindex('' '',@line)+1,     @s2=charindex('' '',@line,@s1)+1,
    @s3=charindex('' '',@line,@s2)+1, @s4=charindex('' '',@line,@s3)+1,
    @s4=charindex('' '',@line,@s3)+1, @s5=charindex('' '',@line,@s4)+1

-- if unix style
if @line like ''[-dl][-r][-w][-xs][-r][-w][-xs][-r][-w][-xs] %[0-9]% % [0-9]% %''
    begin

    -- set language english
    -- select convert(datetime,''Jan 11 2012 13:43'',100)
    -- select convert(datetime,''Jan 11 2012 13:43:01'',100)
    -- select convert(datetime,''Jan 11 2012 1:43PM'',100)
    -- select @@language
    -- set language italian

    select
        @dir=left(@line,1),
        @permissions=substring(@line,2,9),
        @filecode=substring(@line,@s1,@s2-@s1),
        @owner=substring(@line,@s2,@s3-@s2),
        @group=substring(@line,@s3,@s4-@s3),
        @size=substring(@line,@s4,@s5-@s4)

    select @tmp=substring(@line,@s5,128)
    select
        @s1=charindex('' '',@tmp)+1,      -- dd
        @s2=charindex('' '',@tmp,@s1)+1,  -- yy
        @s3=charindex('' '',@tmp,@s2)+1,  -- file or hh:mm or year
        @s4=charindex('' '',@tmp,@s3)+1

    -- unify date to "mmm dd yyyy hh:mm[am|pm]"

    -- winscp format "mmm dd hh:mm:ss yyyy "
    if @tmp like ''[a-z][a-z][a-z]%:%:%''
        begin
        select @dts=left(@tmp,@s2-1)
                   +substring(@tmp,@s3,@s4-@s3)
                   +substring(@tmp,@s2,@s3-@s2),
               @name=substring(@tmp,@s4,128),
               @done=1
        end

    -- month day hour:minute
    if @done=0 and @tmp like ''[a-z][a-z][a-z]%:%''
        begin
        select @dts=left(@tmp,@s2-1)
                   +cast(year(getdate()) as char(4))+'' ''
                   +substring(@tmp,@s2,@s3-@s2),
               @name=substring(@tmp,@s3,128),
               @done=1
        end

    if @done=0
        select @dts=left(@tmp,@s3-1),
               @name=substring(@tmp,@s3,128),
               @done=1

    end -- unit style

-- if microsoft style
if @done=0 and @line like ''[0-9][0-9][-/][0-9][0-9][-/][0-9][0-9] %''
    begin

    select
        @dts=convert(
                sysname,
                convert(datetime,substring(@line,1,8),10)
                +convert(datetime,substring(@line,@s1,7),0),
                100),
        @tmp=substring(@line,@s2,@s3-@s2)
    if isnumeric(@tmp)=1
        select
            @dir=''-'',   -- l is linked file
            @size=convert(int,@tmp),
            @name=substring(@line,@s3,128)
    if @tmp=''''
        select
            @dir=''d'',
            @size=0,
            @name=substring(@line,@s3,128)
    select @done=1
    end -- microsoft style

if @done=1
    insert @t(
        lno,dir,[permissions],filecode,[owner],[group],size,[timestamp],name
        )
    select
        @lno,
        dir=@dir,
        [permissions]=@permissions,
        filecode=@filecode,
        [owner]=@owner,
        [group]=@group,
        [size]=cast(@size as int),
        [timestamp]=@dts,
        name=@name

return
end -- fn__ftp_list_parse'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__ftp_parse_list:

-- ============================================================== fn__job_status
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__job_status',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131127.1100
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__job_status') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__job_status') with nowait
        goto skip_fn__job_status
        end
    if @ver>131127.1100
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__job_status') with nowait
        goto skip_fn__job_status
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__job_status') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__job_status'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__job_status]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:job,status,history,number,execution
    v:131127.1100\s.zaglio: added name
    v:131126.1000\s.zaglio: added from_date
    v:131122\s.zaglio: modified and integrated into sp__job_status
    r:131117\s.zaglio: return history grouped by number of execution
    t:select * from fn__job_status(''%'',30*24*60,default)
    t:select * from fn__job_status(''%status%'',30*24*60,''fle'')
    t:select * from fn__job_status(''%'',30*24*60,''fle'')
*/
CREATE function fn__job_status(
    @jobs nvarchar(4000),       -- jobs separated by |
    @mins int,                  -- minutes back for search (default 24h)
    @opt sysname
    )
returns @rs table (
    row         int null,
    id          uniqueidentifier not null,
    name        sysname not null,
    run_date    int not null,
    run_time    int not null,
    from_time   int not null,
    dt_ss       int null,
    err         bit null,
    n           int null
    )
as
begin
-- ================================================================== options ==

declare
    -- options
    @fle bit    -- from last error

-- ===================================================================== init ==

select @mins=isnull(@mins,7*24*60)
if not @opt is null
    select
        @opt=''|''+@opt+''|'',
        @fle=charindex(''|fle|'',@opt)
else
    select @fle=0

-- ===================================================================== data ==

declare @data table (
    instance_id int,
    row         int null,
    id          uniqueidentifier not null,
    name        sysname not null,
    stp         int not null,
    err         bit null,
    run_date    int not null,
    run_time    int not null,
    dt_ss int null,
    primary key (instance_id desc)
    )

insert @data(instance_id,row,id,name,stp,err,run_date,run_time,dt_ss)
select
    instance_id,
    row =
        row_number() over(order by sjh.job_id,run_date,run_time,sjh.step_id),
    id = sjh.job_id,
    name = j.name,
    stp = sjh.step_id,
    err = cast(case when sjh.sql_severity>10 then 1 else 0 end as bit),
    run_date,
    run_time,
    dt_ss =
        run_duration%100+(run_duration/100%100*60)+
        (run_duration/10000%100*3600)
-- select top 10 *
from msdb..sysjobhistory sjh (nolock)
join msdb..sysjobs j on j.job_id=sjh.job_id
join fn__str_split(@jobs,''|'') on name like token
and run_date>cast(convert(sysname,dateadd(mi,-@mins,getdate()),112) as int)
and sjh.server=@@servername

/* outcome running job
if 0!=(select top 1 stp from @data)
    insert @data
    select top 1 instance_id+1,row,id,name,0,err,run_date,run_time,dt_ss
    from @data
*/

-- ================================================================= outcomes ==

declare @outcomes table(
    orow        int null,
    row         int null,
    id          uniqueidentifier not null,
    name        sysname not null,
    stp         int not null,
    err         bit null,
    run_date    int not null,
    run_time    int not null,
    dt_ss int null
    )

insert @outcomes
select
    orow=row_number() over(order by row),
    row,id,name,stp,err,run_date,run_time,dt_ss
from @data
where stp=1

-- =================================================================== ranges ==

declare @ranges table(
    rrow int null,
    l    int null,
    r    int null
    )

insert @ranges
select
    rrow=row_number() over(order by a.row),
    a.row as l,
    isnull(b.row-1,(select max(row) from @data d where d.id=a.id)) as r
from @outcomes a
left join @outcomes b on isnull(b.orow,a.orow+1)=a.orow+1

-- ========================================================== groups of steps ==

declare @grps table(
    row         int null,
    id          uniqueidentifier not null,
    err         bit null,
    rrow        int null
    )

insert @grps
select data.row,data.id,data.err,ranges.rrow
from @data data
join @ranges ranges
on data.row between ranges.l and ranges.r

-- ===================================================================== runs ==

declare @runs table(
    row  bigint null,
    id   uniqueidentifier not null,
    err  bit null,
    rrow bigint null
    )

insert @runs
select
    min(row) as row,id,
    cast(sum(cast(err as int)) as bit) err,
    rrow
from @grps
group by id,rrow

-- ========================================================== history summary ==

declare @his table(
    row         bigint null,
    id          uniqueidentifier not null,
    name        sysname not null,
    run_date    int not null,
    run_time    int not null,
    dt_ss int null,
    err         bit null
    )

insert @his(row,id,name,run_date,run_time,dt_ss,err)
select
    row=row_number() over (order by data.row),
    data.id,data.name,data.run_date,data.run_time,data.dt_ss,
    runs.err
from @data data
join @runs runs on data.row=runs.row

-- ================================================================== headers ==

declare @heads table(
    row  bigint null,
    hrow bigint null
    )

insert @heads
select cur.row,hrow = row_number() over (order by cur.row)
from @his cur
left join @his prev on cur.row = prev.row+1
where prev.err != cur.err or prev.id != cur.id or cur.row=1

-- ================================================================= his grps ==

declare @his_grps table(
    row         int null,
    id          uniqueidentifier not null,
    run_date    int not null,
    run_time    int not null,
    dt_ss int null,
    err         bit null,
    hrow        bigint null
    )

insert @his_grps(row,id,run_date,run_time,dt_ss,err,hrow)
select  his.row,his.id,his.run_date,his.run_time,his.dt_ss,his.err,
        hrow = (select max(hrow)
                from @heads heads
                where heads.row <= his.row)
from @his his

-- =============================================================== record set ==

if @fle=0
    insert @rs(row,id,name,run_date,run_time,from_time,dt_ss,err,n)
    select
        his.row,his.id,his.name,
        his.run_date,his.run_time,err.run_time,his.dt_ss,
        his.err,err.n
    from @his his
    join (
        select max(row) row,err,count(hrow) n,min(run_time) run_time
        from @his_grps
        group by hrow,err
        ) err on his.row=err.row
    order by row desc
else
    insert @rs(row,id,name,run_date,run_time,from_time,dt_ss,err,n)
    select
        his.row,his.id,his.name,his.run_date,
        his.run_time,err.run_time,his.dt_ss,
        his.err,err.n
    from @his his
    join (
        select max(row) row,err,count(hrow) n,min(run_time) run_time
        from @his_grps
        group by hrow,err
        ) err on his.row=err.row
    join (
        select id,max(row) row
        from @his_grps
        where err=1
        group by id,err
        ) fle on his.id=fle.id and his.row>=fle.row
    order by row desc

return
end -- fn__job_status'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__job_status:

-- ========================================================== fn__ntext_to_lines
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__ntext_to_lines',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110721.1646
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__ntext_to_lines') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__ntext_to_lines') with nowait
        goto skip_fn__ntext_to_lines
        end
    if @ver>110721.1646
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__ntext_to_lines') with nowait
        goto skip_fn__ntext_to_lines
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__ntext_to_lines') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__ntext_to_lines'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__ntext_to_lines]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    g:utility
    v:110721.1646\s.zaglio: alternative use of sp__write_ntext_to_lines
    t:
        declare @obj sysname,@le bit
        select @le=1,@obj=
            ''SP_SAP_EXPORT_PRODUCTIONS_test_bug''
            -- ''sp__write_ntext_to_lines''
        select *,charindex(char(13),line) pcr,charindex(char(10),line) plf
        from fn__ntext_to_lines(
                (select top 1 [text]
                    from syscomments
                    where id=object_id(@obj)
                    )
                ,@le  -- @leave_le
            )
        order by lno
*/
CREATE function fn__ntext_to_lines(@blob ntext,@leave_le bit)
returns @t table(lno int identity primary key,line nvarchar(4000))
as
begin

declare
    @drop bit,
    @i int,@j int,@l int,@n int,@p int,
    @ncrlf nvarchar(2),@cr nchar(1),@lf nchar(1),
    @lcrlf int,@dbg bit

select @dbg=0

declare @lines table (pos int primary key,leng int)

select @ncrlf=crlf,@cr=cr,@lf=lf,@leave_le=isnull(@leave_le,0)
from fn__sym()

-- identify row separator
select
    @i=charindex(@cr,@blob),
    @j=charindex(@lf,@blob),
    @n=datalength(@blob)/2
/*
if @dbg=1
    insert @t(line)
    select ''@i=''+cast(@i as sysname) union
    select ''@j=''+cast(@j as sysname) union
    select ''@n=''+cast(@n as sysname)
*/

if @i is null return
if @i=0 and @j=0 and @n<4000
    begin
    insert @t(line) select substring(@blob,1,4000)
    return
    end

if @i>0 and @j=0 select @ncrlf=@cr
if @i=0 and @j>0 select @ncrlf=@lf
if @i=@j+1 select @ncrlf=@lf+@cr
select @lcrlf=len(@ncrlf)
/*
if @dbg=1
    insert @t(line)
    select ''@lcrlf=''+cast(@lcrlf as sysname) union
    select ''@cr=''+cast(unicode(@cr) as sysname) union
    select ''@lf=''+cast(unicode(@lf) as sysname) union
    select ''@ncrlf=''+cast(unicode(substring(@ncrlf,1,1)) as sysname)+''|''+
                     cast(isnull(unicode(substring(@ncrlf,2,1)),''0'') as sysname)
*/
select top 1 @i=1,@p=1,@j=1

while 1=1
    begin
    select top 1 @i=charindex(@ncrlf,substring(@blob,@j,4000))

    if @i=0
        begin
        -- last pieces that do not end with crlf
        -- if @dbg=1 exec sp__printf ''j:%d, i:%d, @n:%d'',@j,@i,@n
        if @n>@j/*+@lcrlf*/-1 insert @lines select @j,@n-@j+1
        break
        end
    -- if @dbg=1 exec sp__printf ''j:%d, i:%d'',@j,@i
    if @leave_le=1 select @l=@i+@lcrlf-1 else select @l=@i-1
    insert @lines select @j,@l
    /*
    if @dbg=1
        begin
        insert @t(line)
        select left(''i:''+cast(@i as sysname)+
                    '';j:''+cast(@j as sysname)+
                    '';l:''+cast(@l as sysname)+
                    '';                    '',20)+
               replace(replace(substring(@blob,@j,4000),@lf,''|''),@cr,''+'')
        insert @t(line) select space(@i+20-1)+''^''
        end
    */
    select @j=@j+@i+@lcrlf-1
    end -- while

/*
insert @t(line)
select ''pos:''+cast(pos as sysname)+''; leng:''+cast(leng as sysname)
from @lines
return
*/
insert @t(line)
select substring(@blob,pos,leng) line
from @lines

return
end -- fn__ntext_to_lines'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__ntext_to_lines:

-- =============================================================== fn__parse_url
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__parse_url',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130906.1000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__parse_url') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__parse_url') with nowait
        goto skip_fn__parse_url
        end
    if @ver>130906.1000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__parse_url') with nowait
        goto skip_fn__parse_url
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__parse_url') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__parse_url'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__parse_url]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    d:130906\s.zaglio:fn__parseurl
    v:130906.1000\s.zaglio:moved out tests,renamed and + parse of local path
    v:120125\s.zaglio:done
    r:120124\s.zaglio:working
    r:120123\s.zaglio:parse the unified resource locator
    d:120123\s.zaglio:fn__parsefilename
    t:sp__parse_url_test
*/
CREATE function [dbo].[fn__parse_url](
    @url nvarchar(4000),
    @opt sysname
    )
returns @t table(
    url nvarchar(4000) null,
    normalized nvarchar(4000) null,
    protocol sysname null,
    [uid] sysname null,
    [pwd] sysname null,
    host sysname null,
    port sysname null,              -- because can contain the drive/device
    [path] nvarchar(4000) null,
    page nvarchar(4000) null,
    query nvarchar(4000) null,
    dbg sysname null
    )
as
begin
declare
    @dsp as int,                -- double slash position is the fulcrum
    @nurl nvarchar(4000),       -- normalized url
    @ourl nvarchar(4000),       -- original url
    @protocol sysname,
    @uid sysname,
    @pwd sysname,
    @host sysname,
    @port sysname,
    @path nvarchar(4000),
    @page nvarchar(4000),
    @query nvarchar(4000),
    @puid int,@ppwd int,@ppath int,@pquery int,
    @pport int,@ppage int,@lpath int,
    @psep nvarchar(2),@revert bit,
    @dbg sysname

if @url is null goto ret

-- normalize name
select
    @ourl=@url,
    @url=replace(@url,''%20'','' ''),
    @psep=psep
from fn__sym()

-- reduce firefox long file url
select @url=replace(@url,''/////'',''//'')

-- special check for local path
if @url like ''[a-z]:\[^\]%''
    select @url=''file:///''+@url,@revert=1
else
    select @revert=0


-- dsp must be specified
select
    @nurl=replace(@url,''\'',''/''),
    @dsp=charindex(''//'',@nurl),
    @ppath=charindex(''/'',@nurl,@dsp+2),
    @pquery=charindex(''?'',@nurl,@dsp+2)
if @dsp = 0 goto wrong
if @ppath = 0 select @ppath=len(@nurl)+1     -- ftp path can not have it
if @pquery=0 select @pquery=len(@nurl)+1

-- select * from dbo.fn__parse_url(''c:\share\dir\file.ext'',default)

select
    @protocol=left(@url,@dsp-1),
    @host=substring(@url,@dsp+2,@ppath-@dsp-2),
    @path=substring(@url,@ppath,@pquery-@ppath),
    @nurl=reverse(substring(@nurl,@ppath,@pquery-@ppath)),    -- used below
    @query=substring(@url,@pquery+1,4000),
    @ppwd=charindex('':'',@host),
    @puid=charindex(''@'',@host)
    -- ,@dbg=@nurl

if @revert=1 select @path=replace(@path,''/'',''\'')

if @protocol!=''''
    begin
    if right(@protocol,1)!='':'' goto wrong
    else select @protocol=left(@protocol,@dsp-2)
    end

if @ppwd>0
    select
        @pwd=left(@host,@ppwd-1),
        @uid=substring(@host,@ppwd+1,@puid-@ppwd-1),
        @host=substring(@host,@puid+1,128),
        @pport=charindex('':'',@host)

if @pport>0
    begin
    select
        @port=substring(@host,@pport+1,16),
        @host=left(@host,@pport-1)
    if isnumeric(@port)=0 and @protocol!=''file''
        goto wrong      -- or is the case to cause and error? No.
                        -- the parse check the syntax not the semantic
    end

-- parse page name if exists
select
    @lpath=len(@path),
    @ppath=@lpath-charindex(''/'',@nurl)+1,
    @ppage=charindex(''.'',@nurl)
    -- ,@dbg=@nurl

if @ppage>0 select @ppage=@lpath-@ppage+1

if @ppage>@ppath and @ppath>0
    select
        @page=substring(@path,@ppath+1,512),
        @path=left(@path,@ppath)
else
    select
        @page=''''

if @protocol=''file'' and @host=''''
    select
        @host=null,
        @port=substring(@path,2,charindex('':'',@path)-1),
        @path=substring(@path,charindex('':'',@path)+1,512)

insert @t(  url,        normalized,
            protocol,   [uid],  [pwd],  host,
            port,       [path], page,   query,
            dbg
         )
select      @ourl,      @url,
            @protocol,  @uid,   @pwd,   @host,
            @port,      @path,  @page,  @query,
            @dbg

ret:
return
wrong:
insert @t(  url,        normalized,
            protocol,   [uid],  [pwd],  host,
            port,       [path], page,   query,
            dbg
         )
select      @ourl,      null,
            null,       null,   null,   null,
            null,       null,   null,   null,
            null
return
end -- fn__parse_url'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__parse_url:

-- =============================================================== fn__parsename
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__parsename',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100612
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__parsename') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__parsename') with nowait
        goto skip_fn__parsename
        end
    if @ver>100612
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__parsename') with nowait
        goto skip_fn__parsename
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__parsename') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__parsename'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__parsename]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100612\s.zaglio: revision
    r:100404\s.zaglio: returns tsql name splitted
    t:select * from fn__parsename(''svr.db..obj'',0,0)
    t:select * from fn__parsename(''[db]..obj'',0,0)
    t:select * from fn__parsename(''*obj*'',0,1)
    t:select * from fn__parsename(''*obj*'',1,1)
*/
CREATE function [dbo].[fn__parsename](@obj sysname,@quoted bit=0,@defaults bit=0)
returns @t table(svr sysname null,db sysname null,sch sysname null,obj sysname null)
--begin
as
begin
if @obj is null return
declare @svr sysname,@db sysname,@sch sysname,@tbl sysname
select
    @svr=parsename(@obj,4),
    @db=parsename(@obj,3),
    @sch=parsename(@obj,2),
    @tbl=parsename(@obj,1)

if @defaults=1
    select
        @svr=coalesce(@svr,dbo.fn__servername(Null)),
        @db=coalesce(@db,db_name()),
        @sch=coalesce(@sch,''dbo'')

if @quoted=1
    select
        @svr=quotename(@svr),
        @db=quotename(@db),
        @sch=quotename(@sch),
        @tbl=quotename(@tbl)

insert @t select @svr,@db,@sch,@tbl
return
end -- fn__parsename'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__parsename:

-- =================================================================== fn__place
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__place',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121118
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__place') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__place') with nowait
        goto skip_fn__place
        end
    if @ver>121118
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__place') with nowait
        goto skip_fn__place
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__place') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__place'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__place]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:street, place, civic, split, correc, normalize
    v:121118\s.zaglio: working
    v:121007\s.zaglio: split and normalize an address
    t:
        select *
        from tst_street_tbl t
        cross apply fn__place(t.addr,default) p
        cross apply fn__place(t.addr,0) d      -- debug version
        where 1=1
        -- and t.addr=''STR. COMUNALE MARANDA 9''
        and t.addr like ''%riposo%''
        and p.typ_id is null
*/
CREATE function fn__place(@address sysname,@lng tinyint)
returns @t table (
    typ nvarchar(32), typ_id tinyint,
    name nvarchar(128),
    num nvarchar(64)
    -- ,co nvarchar(64)
    )
as
begin
-- declare @addr sysname
declare
    @p_name int,@p_num int,@l int,@p_co int,@p_via int,
    @typ nvarchar(32), @name nvarchar(128), @num nvarchar(64),
    @co nvarchar(64), @typ_id int,@i int,@addr sysname,@j int,
    @c nchar,@pc nchar, @co_id int

-- replace not good symbols: ltrim, rtrim
select @i=1,@l=len(@address),@addr='''',@j=0,@pc='' '',@p_via=0
while @i<=@l
    begin
    select @c=substring(@address,@i,1),@i=@i+1
    -- skip initial spaces
    if (@c=N'' '' and @j=0) continue
    if @c in (''-'','':'') select @c=''.''
    else if @c in (''('','')'','','') select @c='' ''
    -- insert @t(typ,typ_id,name,num) select @pc+''|''+@c+''|'',@i,@addr,@j
    if @pc!='' '' select @addr=@addr+@pc,@j=@j+1
    if @c='' '' and not @pc in (''.'','' '') select @addr=@addr+@c,@j=@j+1
    select @pc=@c
    end
if @c!='' '' select @addr=@addr+@c
-- insert @t(typ,typ_id,name,num) select @pc+''|''+@c+''|'',@i,@addr,@j return

select @addr=replace(replace(@addr,''Rif..'',''''),''Rif.'','''')

-- special cases of address inversion
select top 1 @p_via=charindex(cod,@addr) ,@typ_id=id
-- select *
from fn__place_type()
where charindex(cod,@addr)>0
select top 1 @p_co=charindex(cod,@addr),@co_id=id
-- select *,charindex(cod,''PRESSO CLINICA SAN RAFFAELE'') p_co
from fn__place_at()
where charindex(cod,@addr)>0
select @p_co=isnull(@p_co,0)
if @p_co=1 and @p_via>1
    select @addr=substring(@addr,@p_via,128)+'' ''
                +left(@addr,@p_via-1)

select @l=len(@addr)
if @l<3 goto store

select @p_name=charindex('' '',@addr)
if @p_via=0 and @p_name>0 select @typ=left(@addr,@p_name),@p_name=1

select @p_num=patindex(''%KM%[0-9]%'',@addr)

if @p_num=0 select @p_num=patindex(''%N.[0-9]%'',@addr)

if @p_num=0 select @p_num=patindex(''%N°[0-9]%'',@addr)

if @p_num=0
    begin
    select @p_num=patindex(''%[0-9] %'',reverse(@addr))
    if @p_num>0 select @p_num=@l-@p_num+1
    end

-- if @p_name=0 select @p_name=1

-- select * from arc04_addresses cross apply fn__street(pla)

if not @lng is null
    begin
    insert @t(typ,typ_id,name,num)
    select @p_via,@p_co,@p_name,@p_num
    return
    end

-- if @p_name=0 select @p_name=1
-- if @p_co=0  select @p_co =@l+1
if @p_name>0
    begin
    if @typ is null
        select @typ=ltrim(left(@addr,@p_name-1)),@p_name=@p_name+1 -- skip space
    if @p_num=0 and @p_co=0
        select @name=ltrim(rtrim(substring(@addr,@p_name,abs(@l+1-@p_name))))
    else
        begin
        if @p_num=0 and @p_co>0
            select
                @num=ltrim(rtrim(replace(substring(@addr,@p_co,@l+1-@p_co),'','',''''))),
                @name=ltrim(rtrim(substring(@addr,@p_name,abs(@p_co-@p_name))))
        else
            select
                @num=ltrim(rtrim(replace(substring(@addr,@p_num,@l+1-@p_num),'','',''''))),
                @name=ltrim(rtrim(substring(@addr,@p_name,abs(@p_num-@p_name))))
        end
    end
else
    select @name=@addr

select @name=replace(@name,'','','''')
-- if right(@name,2) in (''n.'','' n'',''n°'') select @name=left(@name,len(@name)-2)

store:
-- exec sp__printf ''pn:%d n:%s'',@p_num,@name

if @name is null
    insert @t select null,@typ_id,@addr,null--,@co
else
    insert @t select @typ,@typ_id,@name,@num--,@co

return
end -- fn__place'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__place:

-- ============================================================== fn__plan_dates
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__plan_dates',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121118
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__plan_dates') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__plan_dates') with nowait
        goto skip_fn__plan_dates
        end
    if @ver>121118
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__plan_dates') with nowait
        goto skip_fn__plan_dates
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__plan_dates') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__plan_dates'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__plan_dates]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,plan
    k:plan,calendar,planning
    r:121118\s.zaglio: convert plan calendar structure into dates
    t:sp__plan_calendar_test
*/
CREATE function fn__plan_dates(
    @year int,
    @days nvarchar(24)    -- 12 int:bit0=01/01
    )
returns @t table (dt datetime)
as
begin
/*
    declare @t table (dt datetime)
    declare @year int,@days varchar(48)
    select @year=2012,@days=cast(1 as varchar(48))
    select cast(@days as varbinary(48))
*/
declare @pmm int,@chunk binary(4),@dt datetime,@dayp2 bigint,@day int,@month int
select
    @dt=0,
    @dt=dateadd(yy,@year-year(0),@dt),
    @month=0,
    @pmm=1

-- select * from dbo.fn__plan_dates(2012,cast(1 as varchar(48)))

while @pmm<=len(@days)
    begin
    select @chunk=cast(substring(@days,@pmm,2) as binary(4))
    select @day=0,@dayp2=1
    while @day<31
        begin
        /*
        exec sp__printf
                ''chunk:%d, pmm:%d, day:%d, dp2:%d'',
                @chunk,@pmm,@day,@dayp2
        */
        if @chunk&@dayp2=@dayp2 insert @t select dateadd(mm,@month,@dt)+@day
        select @day=@day+1,@dayp2=@dayp2*2
        end
    select @pmm=@pmm+2,@month=@month+1
    end

-- select * from @t

return
end -- fn__plan_dates'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__plan_dates:

-- =============================================================== fn__regexfind
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__regexfind',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131009
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__regexfind') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__regexfind') with nowait
        goto skip_fn__regexfind
        end
    if @ver>131009
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__regexfind') with nowait
        goto skip_fn__regexfind
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__regexfind') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__regexfind'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__regexfind]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:131009\s.zaglio:restyle
    v:080101\www.simple-talk.com
    t:
        begin
        --showing the context where two words ''for'' and ''last'' are found in proximity
        DECLARE @sample nvarchar(2000)
        SELECT @Sample=''You have failed me for the last time, Admiral.
        We have not long to wait for your last gasp''
        SELECT ''...''+SUBSTRING(@Sample,Firstindex-8,length+16)+''...''
            FROM dbo.fn__RegexFind (''\bfor(?:\W+\w+){0,3}?\W+last\b'',
                   @sample,1,1)

        --finding repeated words, showing the repetition and the repeated word
        SELECT [repetition]=value, [word]=SubmatchValue FROM dbo.fn__RegexFind (''\b(\w+)\s+\1\b'',
        ''this this is is a repeated word word word'',1,1)

        --Split lines based on a regular expression
        SELECT value FROM dbo.fn__regexfind(''[^\r\n]*(?:[\r\n]*)'',
        ''
        This is the second line
        This is the third
        and the fourth'',1,1) WHERE length>0

        --break up all words in a string into separate table rows
        SELECT value FROM dbo.fn__RegexFind (''\b[\w]+\b'',
        ''Hickory dickory dock,the mouse ran up the clock'',1,1)

        --split ntext into keywords and values
        SELECT Match_ID,
        [keyword]=MAX (CASE WHEN submatch_ID=1 THEN  submatchValue ELSE '''' END),
        [value]=MAX (CASE WHEN submatch_ID=2 THEN  submatchValue ELSE '''' END)
          FROM dbo.fn__RegexFind (''(\w+)\s*=\s*(.*)\s*'',
        ''firstname=Phil
        Lastname=Factor
        Salary=$200,000
        age=unknown to us
        Post=DBA'',1,1) GROUP BY Match_ID

        SELECT * FROM dbo.fn__RegexFind (''([^\|\r\n]+[\|\r\n]+)'',
        ''1|white gloves|2435|24565
        2|Sports Shoes|285678|0987
        3|Stumps|2845|987
        4|bat|29862|4875'',1,1)

        --get valid dates and convert to SQL Server format
        SELECT DISTINCT CONVERT(DATETIME,value,103)
        FROM dbo.fn__RegexFind (''\b(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20?[0-9]{2})\b'',''
        12/2/2006 12:30 <> 13/2/2007
        13:30
        32/3/2007
        2-4-2007
        25.8.2007
        1/1/2005
        34/2/2104
        2/5/2006'',1,1)

        end
*/
CREATE function fn__regexfind(
    @pattern nvarchar(255),
    @matchstring nvarchar(max),
    @global bit = 1,
    @multiline bit =1)
returns
    @result table
        (
        match_id int,
          firstindex int ,
          length int ,
          value nvarchar(2000),
          submatch_id int,
          submatchvalue nvarchar(2000),
         error nvarchar(255)
        )


as -- columns returned by the function
/* this is the most powerful function for doing complex finding and replacing of text.
as it passes back detailed records of the hits, including the location and the backreferences,
it allows for complex manipulations.

this is written as a table function. the regex routine actually passes back a collection for each ''hit''.
in the relational world, you''d normally represent this in two tables, so we''ve returned a left outer join
of the two logical tables so as to pass back all the information.
this seems to cater for all the uses we can think of. we also append an error column, which should be blank!
*/
begin
declare @objregexexp int,
    @objerrorobject int,
    @objmatch int,
    @objsubmatches int,
    @strerrormessage nvarchar(255),
   @error nvarchar(255),
    @substituted nvarchar(4000),
    @hr int,
    @matchcount int,
    @submatchcount int,
    @ii int,
    @jj int,
    @firstindex int,
    @length int,
    @value nvarchar(2000),
    @submatchvalue nvarchar(2000),
    @objsubmatchvalue int,
    @command nvarchar(4000),
    @match_id int

declare @match table
    (
      match_id int identity(1, 1)
                   not null,
      firstindex int not null,
      length int not null,
      value nvarchar(2000)
    )
declare @submatch table
    (
      submatch_id int identity(1, 1),
      match_id int not null,
      submatchno int not null,
      submatchvalue nvarchar(2000)
    )

select  @strerrormessage = ''creating a regex object'',@error=''''
exec @hr= sp_oacreate ''vbscript.regexp'', @objregexexp out
if @hr = 0
    select  @strerrormessage = ''setting the regex pattern'',
            @objerrorobject = @objregexexp
if @hr = 0
    exec @hr= sp_oasetproperty @objregexexp, ''pattern'', @pattern
if @hr = 0
    select  @strerrormessage = ''specifying a case-insensitive match''
if @hr = 0
    exec @hr= sp_oasetproperty @objregexexp, ''ignorecase'', 1
if @hr = 0
    exec @hr= sp_oasetproperty @objregexexp, ''multiline'', @multiline
if @hr = 0
    exec @hr= sp_oasetproperty @objregexexp, ''global'', @global
if @hr = 0
    select  @strerrormessage = ''doing a match''
if @hr = 0
    exec @hr= sp_oamethod @objregexexp, ''execute'', @objmatch out,
        @matchstring
if @hr = 0
    select  @strerrormessage = ''getting the number of matches''
if @hr = 0
    exec @hr= sp_oagetproperty @objmatch, ''count'', @matchcount out
select  @ii = 0
while @hr = 0
    and @ii < @matchcount
    begin
    /*the match object has four read-only properties.
    the firstindex property indicates the number of characters in the string to the left of the match.
    the length property of the match object indicates the number of characters in the match.
    the value property returns the ntext that was matched.*/
        select  @strerrormessage = ''getting the firstindex property'',
                @command = ''item('' + cast(@ii as nvarchar) + '').firstindex''
        if @hr = 0
            exec @hr= sp_oagetproperty @objmatch, @command,
                @firstindex out
        if @hr = 0
            select  @strerrormessage = ''getting the length property'',
                    @command = ''item('' + cast(@ii as nvarchar) + '').length''
        if @hr = 0
            exec @hr= sp_oagetproperty @objmatch, @command, @length out
        if @hr = 0
            select  @strerrormessage = ''getting the value property'',
                    @command = ''item('' + cast(@ii as nvarchar) + '').value''
        if @hr = 0
            exec @hr= sp_oagetproperty @objmatch, @command, @value out
        insert  into @match
                (
                  firstindex,
                  [length],
                  [value]
                )
                select  @firstindex + 1,
                        @length,
                        @value
        select  @match_id = @@identity
        /* the submatches property of the match object is a collection of
        strings. It will only hold values if your regular expression has
        capturing groups. The collection will hold one string for each
        capturing group. The count property (returned as submatchcount)
        indicates the number of string in the collection.
        The item property takes an index parameter, and returns the ntext
        matched by the capturing group.
        */
        if @hr = 0
            select  @strerrormessage = ''getting the submatches collection'',
                    @command = ''item('' + cast(@ii as nvarchar)
                    + '').submatches''
        if @hr = 0
            exec @hr= sp_oagetproperty @objmatch, @command,
                @objsubmatches out
        if @hr = 0
            select  @strerrormessage = ''getting the number of submatches''
        if @hr = 0
            exec @hr= sp_oagetproperty @objsubmatches, ''count'',
                @submatchcount out
        select  @jj = 0
        while @hr = 0
            and @jj < @submatchcount
            begin
                if @hr = 0
                    select  @strerrormessage = ''getting the submatch value property'',
                            @command = ''item('' + cast(@jj as nvarchar)
                            + '')'' ,@submatchvalue=null
                if @hr = 0
                    exec @hr= sp_oagetproperty @objsubmatches, @command,
                        @submatchvalue out
                insert  into @submatch
                        (
                          match_id,
                          submatchno,
                          submatchvalue
                        )
                        select  @match_id,
                                @jj+1,
                                @submatchvalue
                select  @jj = @jj + 1
            end
        select  @ii = @ii + 1
    end
if @hr <> 0
    begin
        declare @source nvarchar(255),
            @description nvarchar(255),
            @helpfile nvarchar(255),
            @helpid int

        execute sp_oageterrorinfo @objerrorobject, @source output,
            @description output, @helpfile output, @helpid output
        select  @error = ''error whilst ''
                + coalesce(@strerrormessage, ''doing something'') + '', ''
                + coalesce(@description, '''')
    end
exec sp_oadestroy @objregexexp
 exec sp_oadestroy        @objmatch
 exec sp_oadestroy        @objsubmatches

insert into @result
      (match_id,
      firstindex,
      [length],
      [value],
      submatch_id,
      submatchvalue,
     error)


select  m.[match_id],
       [firstindex],
       [length],
       [value],[submatchno],
       [submatchvalue],@error
from    @match m
left outer join   @submatch s
on m.match_id=s.match_id
if @@rowcount=0 and len(@error)>0
insert into @result(error) select @error
return
end -- fn__regexfind'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__regexfind:

-- =============================================================== fn__schema_of
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__schema_of',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100328
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__schema_of') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__schema_of') with nowait
        goto skip_fn__schema_of
        end
    if @ver>100328
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__schema_of') with nowait
        goto skip_fn__schema_of
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__schema_of') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__schema_of'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__schema_of]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100328\s.zaglio: return a table with id
    v:100204\s.zaglio: return schema of a table
    t:print dbo.fn__schema_of(''fn__schema_of'')
*/
create function [dbo].[fn__schema_of](@table sysname)
returns @t table ([name] sysname,id int)
as
begin
-- sp__find ''fn__schema_of'' -> fn__comment_types,sp__script
declare @schema sysname
insert @t
select u.name,u.uid
from sysobjects o
join sysusers u on o.uid=u.uid
where o.id=object_id(@table)
return
end -- fn__schema_of'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__schema_of:

-- ===================================================== fn__script_group_select
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__script_group_select',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130922.1101
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__script_group_select') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__script_group_select') with nowait
        goto skip_fn__script_group_select
        end
    if @ver>130922.1101
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__script_group_select') with nowait
        goto skip_fn__script_group_select
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__script_group_select') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__script_group_select'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__script_group_select]

begin try
exec dbo.sp_executesql @statement = N'/*  Leave this unchanged doe MS compatibility
    l:see LICENSE file
    g:utility,script
    d:130922\s.zaglio:fn__object_id
    v:130922.1101\s.zaglio:added lcl and replaced fn__str_parse
    v:130905,130730.1225,130726\s.zaglio:top0;wider nvarchar;a bug when empty group
    r:130708,130703,\s.zaglio: added exclusions;set of core
    r:130518\s.zaglio: select objects for scripting purpose
    t:
        select *
        from fn__script_group_select(''utility'',default,default,default,default)
        order by ord
    t:select * from fn__script_group_select(''utility'',default,default,''@s.zaglio'',default)
    n:https://code.google.com/p/jquerycsvtotable/
    n:http://tablesorter.com/docs/
*/
CREATE function fn__script_group_select(
    @grp        sysname = null,
    @exclude    nvarchar(4000) = null,
    @include    nvarchar(4000) = null,
    @opt        varchar(256) = null,
    @dbg        int = 0
    )
returns @grp_objs table (
    obj_id int null,
    obj sysname,
    xt nvarchar(2) null,
    tag nvarchar(16) default(''v''),
    aut sysname null,
    ver nvarchar(16) null,
    [des] sysname null,
    grp1 sysname null default(''''),
    grp2 sysname null default(''''),
    grp3 sysname null default(''''),
    core bit default(0),                -- basic obj used to define others
    [drop] nvarchar(512) null,
    lcl sysname null,                   -- previous description or last change log
    ord int,
    match bit
    )
as
begin

declare
    @grp_setup sysname,@aut sysname

select @opt=dbo.fn__str_quote(coalesce(@opt,''''),''|'')

if charindex(''|top0|'',@opt)>0 return

if charindex(''|@'',@opt)>0
    select @aut=dbo.fn__str_between(@opt,''|@'',''|'',default)

-- ============================================================= declarations ==

declare @crlf nvarchar(4)

declare @info table (
    obj_id int,obj sysname,tag nvarchar(4),xt varchar(2),
    val1 nvarchar(4000),val2 nvarchar(4000),val3 nvarchar(4000)
    )

declare @excludes table (obj sysname)

-- ===================================================================== body ==

select
    @crlf=crlf,
    @grp_setup=(select top 1 name
                from sys.objects
                where type=''P'' and name like ''%''+@grp+''_setup''
               ),
    @exclude=isnull(@exclude+''|'','''')
            +''tr__script_trace|tr__script_trace_db|%[_]old''
from fn__Sym()

insert @excludes select token
from dbo.fn__str_table(@exclude,''|'')

-- list all revisioned, groups objects info
insert @info(obj_id,obj,xt,tag,val1,val2,val3)
select
    si.obj_id,si.obj,si.xt,si.tag,
    isnull(si.val1,''''),isnull(si.val2,''''),isnull(si.val3,'''')
-- select *
from dbo.fn__script_info(null,''rvg'',0) si

-- removed excluded
delete nfo from @info nfo join @excludes ex on nfo.obj like ex.obj

-- apply group filter
delete obj
from @info obj
where obj.tag=''g'' and not @grp in (obj.val1,obj.val2,obj.val3)

-- insert remaining revisions with grp info
insert into @grp_objs(
    obj_id,obj,xt,tag,ver,aut,
    des,grp1,grp2,grp3
    )
select
    vr.obj_id,vr.obj,vr.xt,vr.tag,left(vr.val1,16) as ver,vr.val2 as aut,
    vr.val3, g.val1,g.val2,g.val3
from @info vr,@info g
where vr.tag in (''r'',''v'') and g.tag=''g'' and vr.obj_id=g.obj_id
and (@aut is null or vr.val2=@aut)

-- insert @grp_objs(obj,aut) select ''qui'',@aut goto ret

-- delete group info to avoid bad next joins
delete @info where tag=''g''

-- deprecated of selected objects
insert into @grp_objs(obj_id,obj,tag,aut,ver,des)
select
    d.obj_id,d.obj,d.tag,d.val2,left(d.val1,16) as ver,
    case when isnumeric(d.val1)=1 then d.val3 else d.val1 end as des
-- select *
from fn__script_info(default,''d'',default) d
join @grp_objs o on d.obj_id=o.obj_id

-- remove deprecated from objects to script if deprecated date is >
delete vr
from @grp_objs vr
join @grp_objs d on vr.obj=d.des
where vr.tag in(''v'',''r'') and d.tag=''d''
-- and isnumeric(d.ver)=1 and d.ver>vr.ver

-- ============================================================ set the order ==

update objs set
    core=case when core.obj is null then 0 else 1 end,
    ord=
        case
        when not core.obj is null
        then core.ord
        else
            case
            when xt=''TD'' then 90                 -- trigger db
            when objs.obj=@grp_setup then 95     -- eXecute tag
            when xt=''U''  then 100
            when xt=''FN'' then 200
            when xt=''IF'' then 210
            when xt=''TF'' then 220
            when xt=''V''  then 300
            else 999
            end
        end,
    [drop]= case tag
            when ''d'' then null
            else so.if_exists+@crlf+''    ''+so.drop_script
            end
from @grp_objs objs
left join (
    select ''fn__script_sign'' obj,   189 as ord  union   -- must be 1st
    select ''tids'',                  192         union
    select ''flags'',                 195         union
    select ''fn__sym'',               198         union
    select ''fn__str_parse'',         201         union
    select ''fn__str_parse_table'',   204         union
    select ''fn__script_info_tags'',  207         union
    select ''fn__script_info'',       210         union
    select ''fn__script_drop'',       213         union
    select ''fn__sysobjects'',        216         union
    select ''fn__script_sysobjs'',    219         union
    select ''fn__str_distance'',      222         union
    select ''sp__deprecate'',         225         union
    select ''sp__script_update'',     228
    ) core on objs.obj=core.obj
join fn__sysobjects(default,default,''drop_script|if_exists|relaxed'') so
on objs.obj_id=so.id

if charindex(''|lcl|'',@opt)>0
    update objs set lcl=lcl.val3
    from @grp_objs objs
    left join dbo.fn__script_info(null,''rv'',1) lcl
    on objs.obj=lcl.obj
    where objs.tag in (''r'',''v'')
/*
    t:
        select *
        from fn__script_group_select(''utility'',default,default,''lcl'',default)
        order by ord
*/
ret:
return
end -- fn__script_group_select'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__script_group_select:

-- ============================================================ fn__sql_def_cols
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__sql_def_cols',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110601
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__sql_def_cols') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__sql_def_cols') with nowait
        goto skip_fn__sql_def_cols
        end
    if @ver>110601
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__sql_def_cols') with nowait
        goto skip_fn__sql_def_cols
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__sql_def_cols') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__sql_def_cols'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__sql_def_cols]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110601\s.zaglio: added columns def
    v:100404\s.zaglio: list simples create table columns
    t:
        create table test_cols(
            a int, b sysname,c bit,d numeric(4,2),
            e varchar(3),f nvarchar(2),
            u uniqueidentifier
            )
        select * into #test from test_cols
        select * from fn__sql_def_cols(''test_cols'',default,default)
        select * from fn__sql_def_cols(''test_cols'',default,''b,d'')
        select * from fn__sql_def_cols(''#test'',default,default)
        drop table #test
        drop table test_cols
    t:select * from systypes order by [type]
*/
CREATE function [dbo].[fn__sql_def_cols](
    @tbl sysname,
    @sep nvarchar(32)='','',
    @excludes nvarchar(4000)=null
    )
returns @cols table (
    fld sysname,def sysname,ord int,sep nchar(1),
    [type] sysname,[prec] nvarchar(32),[scale] nvarchar(32),
    gtype nvarchar(2)   -- N=numeric, S=string, B=binary, V=variant
    )
as
begin
declare @ex table (fld sysname)
if not @excludes is null
    insert @ex
    select token
    from dbo.fn__str_table(@excludes,@sep)

if left(@tbl,1)!=''#''
    insert @cols(fld,def,ord,sep,[type],[prec],scale,gtype)
    select
        c.name fld,
        dbo.fn__sql_def_typ(t.xusertype,t.name,c.length,c.prec,c.scale,c.isnullable) def,
        c.colorder,
        @sep,
        t.name,
        case when c.xtype=c.xusertype then cast(c.prec as sysname)  else null end,
        c.scale,
        case when t.xtype in (35,99,167,231,175,239) then ''S''
             when t.xtype in (34,165,36,173) then ''B''
             when t.xtype in (98) then ''V''
             else ''N''
        end
    from syscolumns c join systypes t on t.xusertype=c.xusertype
    where c.id=object_id(@tbl)
    and not c.name in (select fld from @ex)
else
    insert @cols(fld,def,ord,sep,[type],prec,scale,gtype)
    select
        c.name fld,
        dbo.fn__sql_def_typ(t.xusertype,t.name,c.length,c.prec,c.scale,c.isnullable) def,
        c.colorder,
        @sep,
        t.name,
        case when c.xtype=c.xusertype then cast(c.prec as sysname) else null end,
        c.scale,
        case when t.xtype in (35,99,167,231,175,239) then ''S''
             when t.xtype in (34,165,36,173) then ''B''
             when t.xtype in (98) then ''V''
             else ''N''
        end
    from tempdb..syscolumns c join systypes t on t.xusertype=c.xusertype
    where c.id=object_id(''tempdb..''+@tbl)
    and not c.name in (select fld from @ex)

update @cols set sep='''' where ord=(select max(ord) from @cols)
return
end -- fn__sql_def_cols'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__sql_def_cols:

-- =============================================================== fn__str_sheet
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_sheet',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131006
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_sheet') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_sheet') with nowait
        goto skip_fn__str_sheet
        end
    if @ver>131006
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_sheet') with nowait
        goto skip_fn__str_sheet
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_sheet') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_sheet'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_sheet]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,util_tkns
    v:131006\s.zaglio: optimized sep reduction
    v:130423\s.zaglio: a bug when @sep are spaces
    v:130201\s.zaglio: added str option
    v:121118\s.zaglio: preparing for group option
    v:120305\s.zaglio: now trim is default and addeded regular
    v:111114\s.zaglio: split a text into table by @sep
    t:
        select *
        from fn__str_sheet(''
            first name   last name   11/12/2011   232.43
                first name 1   last name 2    11/12/2011   33.2
            '',
            ''  '',
            default,default
        )
    t:
        select *
        from fn__str_sheet(''
            id  cod     des
            1   a       desc one
            2   b       desc two
            '',
            ''  '',
            default,''regular''
        )
    t:
        select *
        from fn__str_sheet(''
            id
            1
            2
            '',
            '' '',
            default,''regular''
        )
    */
CREATE function [dbo].[fn__str_sheet](
    @text nvarchar(max),
    @sep nvarchar(32),
    @sep_row nvarchar(4),
    @opt sysname)
returns @tbl table(
    id int identity,
    c00 sql_variant null,
    c01 sql_variant null,
    c02 sql_variant null,
    c03 sql_variant null,
    c04 sql_variant null,
    c05 sql_variant null,
    c06 sql_variant null,
    c07 sql_variant null,
    c08 sql_variant null,
    c09 sql_variant null,
    c10 sql_variant null
    )
as
begin
declare
    @c00 sql_variant,@c01 sql_variant,@c02 sql_variant,@c03 sql_variant,
    @c04 sql_variant,@c05 sql_variant,@c06 sql_variant,@c07 sql_variant,
    @c08 sql_variant,@c09 sql_variant,@c10 sql_variant,
    @c00o sql_variant,@c01o sql_variant,@c02o sql_variant,@c03o sql_variant,
    @c04o sql_variant,@c05o sql_variant,@c06o sql_variant,@c07o sql_variant,
    @c08o sql_variant,@c09o sql_variant
declare
    @p00 int,@p01 int,@p02 int,@p03 int,
    @p04 int,@p05 int,@p06 int,@p07 int,
    @p08 int,@p09 int,@p10 int
declare
    @st nvarchar(4000),@line nvarchar(4000),
    @i int,@j int,@pos int,@l int,
    @step int,@v sql_variant,
    @rpt char(1),           -- 1st char of separator that can repeat
    @lrpt int,              -- len of repeater (for future expansions)
    @dsc char(2),           -- double separator code
    @dsci char(2)           -- double separator code inverted

declare
    @notrim bit,            -- remove white space before and inside
    @regular bit,           -- columns are regularly columned
    @group bit,             -- group data when prev. cols as equals
    @str bit                -- do not convert numbers anda dates

if @text is null or @sep is null return

if @sep_row is null select @sep_row=crlf from fn__sym()

--initialize
select
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''),
    @notrim=charindex(''|notrim|'',@opt),
    @regular=charindex(''|regular|'',@opt),
    @group=charindex(''|regular|'',@opt),
    @str=charindex(''|str|'',@opt)

if @notrim=0 select @dsc=char(17)+char(18),@dsci=char(18)+char(17)

select
    @p00=0,
    @st = '''',
    @rpt=left(@sep,1),
    @lrpt=1,
    @step = len(''.''+@sep+''.'')-2
if @sep = '''' and @step=0 select @sep = '' '',@step=1

select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

declare cs cursor local for
    select
        case @notrim when 1 then token else ltrim(rtrim(token)) end
    from fn__str_table(@text,@sep_row)
    where ltrim(rtrim(token))!=''''
    order by pos
open cs
while 1=1
    begin
    fetch next from cs into @line
    if @@fetch_status!=0 break

    -- ============================================================== regular ==
    if @regular=1
        begin
        if charindex(@sep,@line)=0
            select @p00=1,@p01=len(@line)+1
        if @p00=0
            begin
            select @pos=0,@j=1,@l=len(@line)+1,@i=charindex(@sep,@line)
            if @i=0
                select @p00=1,@p01=@l
            else
                while @i!=0
                    begin
                    -- search next col

                    select @i=@i+@step,@pos=@pos+1
                    -- skip multiple separators like spaces
                    while @i<@l and substring(@line,@i,@lrpt)=@rpt select @i=@i+@lrpt
                    -- insert @tbl(c00,c01,c02,c03,c04)
                    -- select @j,@i,@pos,@regular,datalength(@sep)
                    if @pos=1  select @p00=@j,@p01=4000
                    if @pos=2  select @p01=@j,@p02=4000
                    if @pos=3  select @p02=@j,@p03=4000
                    if @pos=4  select @p03=@j,@p04=4000
                    if @pos=5  select @p04=@j,@p05=4000
                    if @pos=6  select @p05=@j,@p06=4000
                    if @pos=7  select @p06=@j,@p07=4000
                    if @pos=8  select @p07=@j,@p08=4000
                    if @pos=9  select @p08=@j,@p09=4000
                    if @pos=10 select @p09=@j,@p10=4000
                    select @j=@i,@i=charindex(@sep,@line,@j)
                    if @i=0 and @j<@l select @i=@l
                    end
                -- wend
            end -- header line

        select
            @c00=substring(@line,@p00,@p01-@p00),@c01=substring(@line,@p01,@p02-@p01),
            @c02=substring(@line,@p02,@p03-@p02),@c03=substring(@line,@p03,@p04-@p03),
            @c04=substring(@line,@p04,@p05-@p04),@c05=substring(@line,@p05,@p06-@p05),
            @c06=substring(@line,@p06,@p07-@p06),@c07=substring(@line,@p07,@p08-@p07),
            @c08=substring(@line,@p08,@p09-@p08),@c09=substring(@line,@p09,@p10-@p09),
            @c10=@c10

        end -- regular
    else
        begin
        if @notrim=0
            begin
            /*
            select @st=@sep+@sep
            while charindex(@st,@line)>0
                select @line=replace(@line,@st,@sep)
            */
            select @line=replace(
                            replace(
                                replace(@line,@sep,@dsc),@dsci,''''
                                ),@dsc,@sep
                            )
            end

        select @j=1,@pos=0,@line=@line,@l=len(@line)+1
        select @i = charindex(@sep, @line)
        if @i=0 select @i=@l
        select @c00=null,@c01=null,@c02=null,@c03=null,@c04=null,
               @c05=null,@c06=null,@c07=null,@c08=null,@c09=null

        while (@i <> 0)
            begin
            select @st=substring(@line, @j, @i - @j)
            if @notrim=0 select @st=ltrim(rtrim(@st))

            /*  this return an error
            select @v=
                case
                -- when isdate(@st)=1              then convert(datetime,@st)
                when dbo.fn__isnumeric(@st)=1   then convert(int,@st)
                else @st
                end
            */
            -- insert @tbl(c00,c01,c02,c03) select @pos,@i,@j,@st

            select @pos=@pos+1,
                   @j=@i+@step,
                   @i=charindex(@sep, @line,@j)
            if @i=0 and @j<@l select @i=@l

            if @str=1
                select @v=@st
            else
                begin
                if dbo.fn__isnumeric(@st)=1
                    select @v=convert(float,@st)
                else
                    select @v=@st
                end
            if @pos= 1 begin select @c00=@v continue end
            if @pos= 2 begin select @c01=@v continue end
            if @pos= 3 begin select @c02=@v continue end
            if @pos= 4 begin select @c03=@v continue end
            if @pos= 5 begin select @c04=@v continue end
            if @pos= 6 begin select @c05=@v continue end
            if @pos= 7 begin select @c06=@v continue end
            if @pos= 8 begin select @c07=@v continue end
            if @pos= 9 begin select @c08=@v continue end
            if @pos=10 begin select @c09=@v continue end

            end -- while cols

        end -- not regular

        -- store
        insert  @tbl select @c00,@c01,@c02,@c03,@c04,@c05,@c06,@c07,@c08,@c09,@c10
        select  @c00=@c00o,@c01=@c01o,@c02=@c02o,@c03=@c03o,@c04=@c04o,
                @c05=@c05o,@c06=@c06o,@c07=@c07o,@c08=@c08o,@c09=@c09o,@c10=@c10

    end -- while of cursor
close cs
deallocate cs

return
end -- fn__str_sheet'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_sheet:

-- =============================================================== fn__str_table
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_table',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130415
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_table') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_table') with nowait
        goto skip_fn__str_table
        end
    if @ver>130415
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_table') with nowait
        goto skip_fn__str_table
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_table') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_table'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_table]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:%licence%
    g:utility
    v:130415\s.zaglio: 4000->max
    v:120906\s.zaglio: replaced version with "with" because limited to 100 recursions
    v:111114\s.zaglio: added to grp util_tkns and commented inside a 20% faster method mssql2k5>
    v:101201\s.zaglio: added pkey index on pos
    v:100916\s.zaglio: added cross apply example
    v:100314\s.zaglio: managed null @data
    v:090812\s.zaglio: a bug with double sep
    v:081130\s.zaglio: verticalizee a splitted variable
    t:select * from dbo.fn__str_table(''a|b|c'',''|'')
    t:select * from dbo.fn__str_table(''a\n\nc'',''\n'') <-- is correct have only one line empty
    t:select * from dbo.fn__str_table(null,'';'')
    t:select * from dbo.fn__str_table(''a b c d'','''')
    t:
        select l,s.* from (
            select ''1|a|aa'' as l union
            select ''2|b|bb'' as l union
            select ''3|c|cc'' as l union
            select ''4|d|dd'' as l
        ) as data
        cross apply dbo.fn__str_table(data.l,''|'') s
*/
create function [dbo].[fn__str_table](
  @data nvarchar (max),
  @sep nvarchar (32)=''|''
  )
returns
    @t table (pos int identity(1,1) primary key, token nvarchar(4000))
begin
declare @st nvarchar(max)
declare @pos int,@opos int
declare @step int

if @data is null or @sep is null return

--initialize
select @st = ''''
select @step = len(''.''+@sep+''.'')-2
if @sep = '''' and @step=0 select @sep = '' '',@step=1

select @data = @data + @sep , @opos=1
select @pos = charindex(@sep, @data)

while (@pos <> 0)
    begin
    set @st = substring(@data, @opos, @pos - @opos)
    insert into @t (token) values (@st)
    set @opos=@pos+@step
    set @pos = charindex(@sep, @data,@opos)
    end

return
end -- fn__str_table'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_table:

-- =========================================================== fn__str_unpattern
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_unpattern',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120528
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_unpattern') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_unpattern') with nowait
        goto skip_fn__str_unpattern
        end
    if @ver>120528
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_unpattern') with nowait
        goto skip_fn__str_unpattern
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_unpattern') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_unpattern'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_unpattern]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    g:utility
    v:120528\s.zaglio: extract only what change
    t:
        select * from fn__str_unpattern(''
        Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 101
        error(-811561914) "local object "FN_GET_2OF5_CHECKDIGIT" is different" in "sp__script_alias"
        Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 102
        error(-811561914) "local object "FN_GET_3OF9_CHECKDIGIT" is different" in "sp__script_alias"
        Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103
        error(-811561914) "local object "FN_GET_ID_ENTITY_FROM_CD_ERP_SHIPMENT" is different" in "sp__script_alias"
        Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103
        error(-811561914) "local object "SP_MANAGE_MAIL_QUEUE" is different" in "sp__script_alias"
        Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103
        error(-811561914) "local object "SP_REFRESH_VIEWS" is different" in "sp__script_alias"
        '',''[0-9]%'',''unlike'') -- excludes 101 and 102

*/
create function fn__str_unpattern(
    @blob ntext,            -- text
    @filter sysname,        -- value for optional condition
    @opt sysname            -- conditions
    )
returns @t table(lno int,line nvarchar(4000))
as
begin

declare
    @drop bit,
    @i int,@j int,@l int,@n int,@p int,
    @ncrlf nvarchar(2),@cr nchar(1),@lf nchar(1),
    @lcrlf int,@dbg bit,
    @line nvarchar(4000),@lno int,
    @diff int

select @dbg=0

declare @words table (word sysname)
declare @src table (lno int identity primary key,line nvarchar(4000))

select
    @ncrlf=crlf,@cr=cr,@lf=lf,
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')
from fn__sym()

insert @src select ltrim(rtrim(line)) from fn__ntext_to_lines(@blob,0)

-- delete all identic lines
delete from @src
where line in (
    select line from @src group by line having count(*)>1
    )

-- isolate duplicated words
insert @words(word)
select token
from @src src
cross apply fn__str_table(line,'''') b
group by token
having count(*)>1

-- remove duplicated from lines
declare cs cursor local for
    select lno,line
    from @src
open cs
while 1=1
    begin
    fetch next from cs into @lno,@line
    if @@fetch_status!=0 break
    update @words set @line=replace(@line,word,'''') from @words
    select @line=ltrim(rtrim(@line))
    if isnull(@line,'''')='''' continue
    while left(@line,1) in ('''''''',''"'',''['',''('',''{'') and
          right(@line,1) in ('''''''',''"'','']'','')'',''}'')
        select @line=substring(@line,2,len(@line)-2)
    insert @t(lno,line) select @lno,@line
    end -- while of cursor
close cs
deallocate cs

if @opt!=''||''
    begin
    if charindex(''|unlike|'',@opt)>0 and not @filter is null
        delete from @t where line like @filter
    if charindex(''|like|'',@opt)>0 and not @filter is null
        delete from @t where not line like @filter
    end

return
end -- fn__str_unpattern'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_unpattern:

-- =============================================================== fn__str_words
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__str_words',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130509
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__str_words') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__str_words') with nowait
        goto skip_fn__str_words
        end
    if @ver>130509
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__str_words') with nowait
        goto skip_fn__str_words
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__str_words') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__str_words'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__str_words]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,util_tkns
    v:130509\s.zaglio: a small bug on last word
    v:130505\s.zaglio: added min option
    v:120403\s.zaglio: remake of csv parse using (faster) code
    v:120402\s.zaglio: refine of csv option using (slow) regexp
    v:120329\s.zaglio: added more columns and csv option
    v:111114\s.zaglio: split a line into words by @sep
    t:
        select * from fn__str_words('' first name   last name   age  '','' '',default)
        select * from fn__str_words('' first name   last name   age  '',''  '',default)
        select * from fn__str_words(''   first name     last name   age  '',''  '',default)
        select * from fn__str_words(''   first name     last name   age  '',''  '',''min'')
    t:
        select * from fn__str_words(''a,b,c,"d""",e,"",".,.",f'','','',default)
        select * from fn__str_words(''a,b,c,"d""",e,"",".,.,.",f,",",g'','','',''csv'')
*/
CREATE function [dbo].[fn__str_words](
    @line nvarchar(4000),
    @sep nvarchar(32),
    @opt sysname)
returns @tbl table(
    c00 nvarchar(4000) null,
    c01 nvarchar(4000) null,
    c02 nvarchar(4000) null,
    c03 nvarchar(4000) null,
    c04 nvarchar(4000) null,
    c05 nvarchar(4000) null,
    c06 nvarchar(4000) null,
    c07 nvarchar(4000) null,
    c08 nvarchar(4000) null,
    c09 nvarchar(4000) null,
    c10 nvarchar(4000) null,
    c11 nvarchar(4000) null,
    c12 nvarchar(4000) null,
    c13 nvarchar(4000) null,
    c14 nvarchar(4000) null,
    c15 nvarchar(4000) null,
    c16 nvarchar(4000) null,
    c17 nvarchar(4000) null,
    c18 nvarchar(4000) null,
    c19 nvarchar(4000) null,
    c20 nvarchar(4000) null,
    c21 nvarchar(4000) null,
    c22 nvarchar(4000) null,
    c23 nvarchar(4000) null,
    c24 nvarchar(4000) null,
    c25 nvarchar(4000) null,
    c26 nvarchar(4000) null,
    c27 nvarchar(4000) null,
    c28 nvarchar(4000) null,
    c29 nvarchar(4000) null,
    c30 nvarchar(4000) null,
    c31 nvarchar(4000) null
    )
as
begin
/*
    declare @n int select @n=32
    -- generate table cols
    select ''    c''+row+'' nvarchar(4000) null,''
    from (
        select right(''00''+cast(row as varchar),2) row
        from fn__range(0,@n-1,1)
        ) a

    -- generate vars
    select ''    @c''+row+'' nvarchar(4000),''
    from (
        select right(''00''+cast(row as varchar),2) row
        from fn__range(0,@n-1,1)
        ) a

    -- generate if
    select ''    ''+
        ''if @pos=''+row+'' begin ''+
        ''select @c''+right(''00''+row,2)+''=@v continue end''
    from (
        select right(''00''+cast(row as varchar),2) row
        from fn__range(0,@n-1,1)
        ) a

    -- generate col of select
    select ''    @c''+row+'',''
    from (
        select right(''00''+cast(row as varchar),2) row
        from fn__range(0,@n-1,1)
        ) a

    -- generate col of select for rxp
    select ''    select @c''+row+''=token from @rr where id=''+row
    from (
        select right(''00''+cast(row as varchar),2) row
        from fn__range(0,@n-1,1)
        ) a

*/

declare
    @c00 nvarchar(4000),
    @c01 nvarchar(4000),
    @c02 nvarchar(4000),
    @c03 nvarchar(4000),
    @c04 nvarchar(4000),
    @c05 nvarchar(4000),
    @c06 nvarchar(4000),
    @c07 nvarchar(4000),
    @c08 nvarchar(4000),
    @c09 nvarchar(4000),
    @c10 nvarchar(4000),
    @c11 nvarchar(4000),
    @c12 nvarchar(4000),
    @c13 nvarchar(4000),
    @c14 nvarchar(4000),
    @c15 nvarchar(4000),
    @c16 nvarchar(4000),
    @c17 nvarchar(4000),
    @c18 nvarchar(4000),
    @c19 nvarchar(4000),
    @c20 nvarchar(4000),
    @c21 nvarchar(4000),
    @c22 nvarchar(4000),
    @c23 nvarchar(4000),
    @c24 nvarchar(4000),
    @c25 nvarchar(4000),
    @c26 nvarchar(4000),
    @c27 nvarchar(4000),
    @c28 nvarchar(4000),
    @c29 nvarchar(4000),
    @c30 nvarchar(4000),
    @c31 nvarchar(4000)

declare
    @st nvarchar(4000),
    @i int,@j int,@pos int,@l int,
    @step int,@v nvarchar(4000),
    @tmp nvarchar(4000),            -- temporary @v for csv use
    @csv int,                       -- enabled csv management
    @wd nchar(1),                   -- csv word delimiter
    @minimize bit,                  -- reduce multi-sep to one
    @dbg bit,                       -- enable returns of dbg info
    @dsep nvarchar(64),
    @end_declare bit

if @line is null or @sep is null return

-- options
if not @opt is null
    begin
    select @opt=''|''+@opt+''|''
    -- comma separated values
    select @csv=charindex(''|csv'',@opt)
    select @minimize=charindex(''|min|'',@opt)
    select @dbg=charindex(''|dbg|'',@opt)
    if @csv>0 select @wd=''"'',@csv=1
    end
else
    select @minimize=0,@csv=0

--initialize
select @st = ''''
select @step = len(''.''+@sep+''.'')-2
if @sep = '''' and @step=0 select @sep = '' '',@step=1

/*
if @minimize=1
    begin
    select @dsep=@sep+@sep
    while charindex(@dsep,@line)>0 select @line=replace(@line,@dsep,@sep)
    -- return
    end
*/

-- if right(@line,@step)!=@sep select @line = @line + @sep
select @j=1,@pos=-1
select @i = charindex(@sep, @line),@l=len(@line+''.'')

if @dbg=1
    insert @tbl(c00,c01,c02,c03,c04,c05,c06)
    select ''@line'',''@i'',''@j'',''@step'',''@sep'',''@v'',''@l''


while (@j<@l)
    begin

    select @v=substring(@line, @j, @i - @j)

    if @dbg=1
        insert @tbl(c00,c01,c02,c03,c04,c05,c06)
        select @line, @i,@j,@step,@sep,@v,@l

    -- skip multi-separators
    if @minimize=1
        while @i<@l and substring(@line,@i+@step,@step)=@sep
            select @i=@i+@step

    select @j=@i+@step

    /*
        select * from fn__str_words(
            ''   first name     last name   age  4'',''  '',
           --1234567890123456789012345678901234567890
           --  0          1   1         2 3   3
            ''min|dbg''
        )
        select * from fn__str_words(
            ''   first name     last name   age  4'',''  '',
            ''dbg''
        )
    */

    select @i = charindex(@sep, @line,@j)
    if @i=0 select @i=@l

    if @csv=0
        select @pos=@pos+1
    else
        begin

        if @v=@wd
            begin
            if @tmp is null
                select @tmp=@wd+@sep,@v=null
            else
                select @v=@tmp+@wd,@tmp=null
            end

        if not @v is null
            begin
            if left(@v,1)=@wd and right(@v,1)=@wd
                select @pos=@pos+1,@v=replace(substring(@v,2,len(@v)-2),@wd+@wd,@wd)
            else
                begin
                if left(@v,1)!=@wd and @tmp is null
                    select @pos=@pos+1
                else
                    begin
                    if right(@v,1)=@wd
                        select
                            @v=replace(
                                    substring(@tmp+@v,2,len(@tmp)+len(@v)-2),
                                    @wd+@wd,@wd
                                    ),
                            @pos=@pos+1,
                            @tmp=null
                    else
                        select @tmp=isnull(@tmp,'''')+@v+@sep,@v=null
                    end
                end -- half value
            end -- if @v
        end -- csv

    if not @v is null
        begin
        if @pos=00 begin select @c00=@v continue end
        if @pos=01 begin select @c01=@v continue end
        if @pos=02 begin select @c02=@v continue end
        if @pos=03 begin select @c03=@v continue end
        if @pos=04 begin select @c04=@v continue end
        if @pos=05 begin select @c05=@v continue end
        if @pos=06 begin select @c06=@v continue end
        if @pos=07 begin select @c07=@v continue end
        if @pos=08 begin select @c08=@v continue end
        if @pos=09 begin select @c09=@v continue end
        if @pos=10 begin select @c10=@v continue end
        if @pos=11 begin select @c11=@v continue end
        if @pos=12 begin select @c12=@v continue end
        if @pos=13 begin select @c13=@v continue end
        if @pos=14 begin select @c14=@v continue end
        if @pos=15 begin select @c15=@v continue end
        if @pos=16 begin select @c16=@v continue end
        if @pos=17 begin select @c17=@v continue end
        if @pos=18 begin select @c18=@v continue end
        if @pos=19 begin select @c19=@v continue end
        if @pos=20 begin select @c20=@v continue end
        if @pos=21 begin select @c21=@v continue end
        if @pos=22 begin select @c22=@v continue end
        if @pos=23 begin select @c23=@v continue end
        if @pos=24 begin select @c24=@v continue end
        if @pos=25 begin select @c25=@v continue end
        if @pos=26 begin select @c26=@v continue end
        if @pos=27 begin select @c27=@v continue end
        if @pos=28 begin select @c28=@v continue end
        if @pos=29 begin select @c29=@v continue end
        if @pos=30 begin select @c30=@v continue end
        if @pos=31 begin select @c31=@v continue end
        end

    end -- word loop

insert @tbl
select
    @c00,
    @c01,
    @c02,
    @c03,
    @c04,
    @c05,
    @c06,
    @c07,
    @c08,
    @c09,
    @c10,
    @c11,
    @c12,
    @c13,
    @c14,
    @c15,
    @c16,
    @c17,
    @c18,
    @c19,
    @c20,
    @c21,
    @c22,
    @c23,
    @c24,
    @c25,
    @c26,
    @c27,
    @c28,
    @c29,
    @c30,
    @c31
return
end -- fn__str_words'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__str_words:

-- ============================================================ fn__trace_events
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__trace_events',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131006
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__trace_events') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__trace_events') with nowait
        goto skip_fn__trace_events
        end
    if @ver>131006
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__trace_events') with nowait
        goto skip_fn__trace_events
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__trace_events') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__trace_events'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__trace_events]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:131006\s.zaglio:svr->srv
    v:120213\s.zaglio:back to cod/des notation
    v:110312\s.zaglio:list sysobjects types
    t:select * from fn__trace_events(default,default,default)
    t:sp__find ''events''
*/
CREATE function fn__trace_events(@p1 bit=null,@p2 bit=null,@p3 bit=null)
returns @events table (
    id int,rid int,flags smallint null,
    cod sysname
    )
as
begin
-- see entire list in
-- ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.it/udb9/html/fb2a7bd0-2347-488c-bb75-734098050c7c.htm
declare @svr smallint,@db smallint
select top 1 @svr=srv|ddl,@db=db|ddl from flags
insert @events(id,      rid,    flags,  cod)
        select 010,      null,   @svr,   ''DDL_SERVER_LEVEL_EVENTS''
union   select 011,      010,    @svr,   ''create_database''
union   select 012,      010,    @svr,   ''alter_database''
union   select 013,      010,    @svr,   ''drop_database''
union   select 070,      010,    @db,    ''DDL_DATABASE_LEVEL_EVENTS''

union   select 080,      070,    @db,    ''DDL_TABLE_VIEW_EVENTS''

union   select 090,      080,    @db,    ''DDL_TABLE_EVENTS''
union   select 091,      090,    @db,    ''create_table''
union   select 092,      090,    @db,    ''alter_table''
union   select 093,      090,    @db,    ''drop_table''

union   select 100,      080,    @db,    ''DDL_TABLE_EVENTS''
union   select 101,      100,    @db,    ''create_view''
union   select 102,      100,    @db,    ''alter_view''
union   select 103,      100,    @db,    ''drop_view''

union   select 110,      080,    @db,    ''DDL_INDEX_EVENTS''
union   select 111,      110,    @db,    ''create_index''
union   select 112,      110,    @db,    ''alter_index''
union   select 113,      110,    @db,    ''drop_index''
union   select 114,      110,    @db,    ''create_xml_index''

union   select 130,      070,    @db,    ''DDL_SYNONYM_EVENTS''
union   select 131,      130,    @db,    ''create_synonym''
union   select 132,      130,    @db,    ''drop_synonym''

union   select 140,      070,    @db,    ''DDL_FUNCTION_EVENTS''
union   select 141,      140,    @db,    ''create_function''
union   select 142,      140,    @db,    ''alter_function''
union   select 143,      140,    @db,    ''drop_function''

union   select 150,      070,    @db,    ''DDL_PROCEDURE_EVENTS''
union   select 151,      150,    @db,    ''create_procedure''
union   select 152,      150,    @db,    ''alter_procedure''
union   select 153,      150,    @db,    ''drop_procedure''

union   select 160,      070,    @db,    ''DDL_TRIGGER_EVENTS''
union   select 161,      160,    @db,    ''create_trigger''
union   select 162,      160,    @db,    ''alter_trigger''
union   select 163,      160,    @db,    ''drop_trigger''

union   select 170,      070,    @db,    ''DDL_TYPE_EVENTS''
union   select 171,      170,    @db,    ''create_type''
union   select 173,      170,    @db,    ''drop_type''

union   select 200,      070,    @db,    ''DDL_DATABASE_SECURITY_EVENTS''

union   select 220,      200,    @db,    ''DDL_USER_EVENTS''
union   select 221,      220,    @db,    ''create_user''
union   select 222,      220,    @db,    ''alter_user''
union   select 223,      220,    @db,    ''drop_user''

union   select 230,      200,    @db,    ''DDL_ROLE_EVENTS''
union   select 231,      230,    @db,    ''create_role''
union   select 232,      230,    @db,    ''alter_role''
union   select 233,      230,    @db,    ''drop_role''

union   select 250,      200,    @db,    ''DDL_SCHEMA_EVENTS''
union   select 251,      250,    @db,    ''create_schema''
union   select 252,      250,    @db,    ''alter_schema''
union   select 253,      250,    @db,    ''drop_schema''

union   select 260,      200,    @db,    ''DDL_GDR_DATABASE_EVENTS''
union   select 261,      260,    @db,    ''grant_database''
union   select 262,      260,    @db,    ''deny_database''
union   select 263,      260,    @db,    ''revoke_database''

return
end -- fn__trace_events'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__trace_events:

-- =================================================================== fn__xtype
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='fn__xtype',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110312
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'fn__xtype') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'fn__xtype') with nowait
        goto skip_fn__xtype
        end
    if @ver>110312
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'fn__xtype') with nowait
        goto skip_fn__xtype
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'fn__xtype') with nowait

if exists(
    select top 1 null from sys.objects
    where name='fn__xtype'

    and schema_id=schema_id('dbo')
    )
    drop function [dbo].[fn__xtype]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110312\s.zaglio:list sysobjects types
    t:select * from fn__xtype()
    t:
        select *
        from (
            select distinct xtype from sysobjects
            ) t
        left join fn__xtype() f
        on t.xtype=f.xtype
    t:select * from sysobjects where xtype in (''it'',''sq'')
*/
CREATE function fn__xtype()
returns @xtype table ([xtype] nvarchar(2),[name] sysname,sqlver int null)
as
begin
insert @xtype
        select ''C'', ''vincolo CHECK'',null
union   select ''D'', ''valore predefinito o vincolo DEFAULT'',null
union   select ''F'', ''vincolo FOREIGN KEY'',null
union   select ''L'', ''log'',null
union   select ''FN'',''funzione scalare'',null
union   select ''IF'',''funzione inline valutata a livello di tabella'',null
union   select ''P'', ''stored procedure'',null
union   select ''PK'',''vincolo PRIMARY KEY (tipo K)'',null
union   select ''RF'',''stored procedure del filtro di replica'',null
union   select ''S'', ''tabella di sistema'',null
union   select ''TF'',''funzione di tabella'',null
union   select ''TR'',''trigger'',null
union   select ''U'', ''tabella utente'',null
union   select ''UQ'',''vincolo UNIQUE (tipo K)'',null
union   select ''V'', ''vista'',null
union   select ''X'', ''stored procedure estesa'',null
union   select ''SN'',''sininimo'',2005
union   select ''AF'',''funzione di aggregazione (CLR)'',2005
union   select ''PC'',''stored procedure assembly (CLR)'',2005
union   select ''FS'',''funzione scalare assembly (CLR)'',2005
union   select ''FT'',''funzione valutata a livello di tabella assembly (CLR)'',2005
union   select ''R'', ''regola (tipo obsoleto, autonoma)'',2005
union   select ''SQ'',''coda di servizio'',2005
union   select ''TA'',''trigger DML assembly (CLR)'',2005
union   select ''TR'',''trigger DML SQL'',2005
union   select ''UQ'',''vincolo UNIQUE'',2005
union   select ''IT'',''tabella interna'',2005

return
end -- fn__xtype'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_fn__xtype:

-- ======================================================================= enums
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='enums',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130217
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'enums') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'enums') with nowait
        goto skip_enums
        end
    if @ver>130217
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'enums') with nowait
        goto skip_enums
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'enums') with nowait

if exists(
    select top 1 null from sys.objects
    where name='enums'

    and schema_id=schema_id('dbo')
    )
    drop view [dbo].[enums]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this for other app
    l:see LICENSE file
    g:obj,utility
    v:130217\s.zaglio: generic enumerators
*/
CREATE view enums
as
select
    -- fn__str_between
  null as [btw.close_left],     -- search @from and then the next @to
     1 as [btw.close_right],    -- search @to and then the previous @from

    -- end
     -1 as [last]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_enums:

-- ================================================================== sp__backup
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__backup',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120726
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__backup') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__backup') with nowait
        goto skip_sp__backup
        end
    if @ver>120726
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__backup') with nowait
        goto skip_sp__backup
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__backup') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__backup'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__backup]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:120726\s.zaglio: print more info
    v:110324\s.zaglio: modern version
    v:081130\S.Zaglio: rewrited version for general porpouse backup. See also sp__restore
    t:declare @r int exec @r=sp__backup ''%temp%'',@dbg=1,@opt=''doit'' exec sp__printf ''result:%s'',@r
    t:xp__cmdshell ''del "%temp%\*.bak"''
*/
CREATE proc [dbo].[sp__backup]
    @device     nvarchar(1024)=null out,
    @db         sysname=null,
    @opt        sysname=null,
    @dbg        int=0
as
begin
set nocount on

declare @proc sysname,@ret int
select  @proc=object_name(@@procid),@ret=0,
        @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

if @device is null goto help

declare @tmp nvarchar(1024),@dt sysname,@sql nvarchar(4000)

if @db is null select @db=db_name()
select @dt=convert(nvarchar(16),getdate(),12)+''_''+left(replace(convert(nvarchar(16),getdate(),108),'':'',''''),4)

exec sp__get_temp_dir @tmp out
select @tmp=@tmp+''\''+@db+''_''+@dt+''.bak''

if @dbg=1 exec sp__printf ''dev=%s, tmp=%s, db=%s, dt=%s'',@device, @tmp,@db,@dt

-- return the temp file name
if @device=''%temp%'' select @device=@tmp

select @device=replace(@device,''%db%'',@db)
select @device=replace(@device,''%t%'',@dt)

if @dbg=1 exec sp__printf ''dev=%s, tmp=%s, db=%s, dt=%s'',@device, @tmp,@db,@dt

-- if not dest path specified
if left(@device,2)=''\\'' goto err_net

/*
for net feature
if not @move_to is null begin

    declare @src nvarchar(512)
    declare @cmd nvarchar(1024)
    set @src=@dst
    set @bak=dbo.fn__str_at(@move_to,''|'',1)
    set @uid=coalesce(dbo.fn__str_at(@move_to,''|'',2),'''')
    set @pwd=coalesce(dbo.fn__str_at(@move_to,''|'',3),'''')

    if @uid<>'''' or @pwd<>'''' begin
        set @i=charindex(''\\'',@bak)
        if @i<>0 set @i=@i+2
        set @i=charindex(''\'',@bak,@i)
        set @cmd=''net use ''+substring(@bak,1,@i-1)+'' ''+@pwd+'' /user:''+@uid
        if @dbg=1 and @simul=0 print @cmd
        if @simul=1 print @cmd
        if @simul=0 exec sp__run_cmd @cmd,@tmp_table=@tmp_table out,@nodrop=1,@nooutput=@out
    end
    if @simul=0 begin            -- insert backup command
        set @cmd=''insert into ''+@tmp_table+'' values (''''''+dbo.fn__inject(@sql)+'''''')''
        exec(@cmd)
    end
-- t: sp__backup @device=''\\gamon\Backup\%db_name%.bak|seldom\stefano|prova'',@simul=0
    set @cmd=''copy "''+@src+''" "''+@bak+''"''
    if @dbg=1 and @simul=0 print @cmd
    if @simul=0 exec sp__run_cmd @cmd,@tmp_table=@tmp_table out,@nodrop=1,@nooutput=@out
    else print @cmd
    if @uid<>''''  or @pwd<>'''' begin
        set @i=charindex(''\\'',@bak)
        if @i<>0 set @i=@i+2
        set @i=charindex(''\'',@bak,@i)
        set @cmd=''net use ''+substring(@bak,1,@i-1)+'' /delete''
        if @dbg=1 and @simul=0 print @cmd
        if @simul=0 exec sp__run_cmd @cmd,@tmp_table=@tmp_table,@nodrop=1,@nooutput=@out
        else print @cmd
    end

    -- delete local backup
    set @cmd=''del /q "''+@src+''"''
    if @dbg=1 and @simul=0 print @cmd
    if @simul=0 exec sp__run_cmd @cmd,@tmp_table=@tmp_table out,@nodrop=1,@nooutput=@out
    else print @sql
    end
*/
select @sql =''BACKUP DATABASE [''+isnull(@db,''?db?'')+'']''
            +'' TO  DISK = '''''' + isnull(@device,''?device?'') + ''''''''
            +'' WITH NAME = N''''FROM SP__BACKUP'''',  STATS = 10''

if charindex(''|diff|'',@opt)>0
    select @sql=@sql+'',NOSKIP,NOINIT,NOUNLOAD,DIFFERENTIAL''
else
    select @sql=@sql+'',INIT,FORMAT''

if charindex(''|doit|'',@opt)>0
or charindex(''|run|'',@opt)>0
    begin
    exec(@sql)
    if @@error!=0 select @ret=-2
    else
        exec sp__printf ''-- sp__restore new_db,''''%s'''',@opt=''''run'''''',@device
    end
else
    exec sp__printf ''%s'',@sql

dispose:
goto ret

-- =================================================================== errors ==
err_net:    exec @ret=sp__err ''not yet implemented'',@proc goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    backup a db to a file that can be local, a temp dir or a network path

Parameters
    @device     file or net path or %temp% if want a fast backup into tmp dir
                if start with \\ can add usr and pwd at end, separated by |
                can contain %db%, %t% that will be replaced with db name and time stamp
    @db         if not current db
    @opt        options
                run     modern version of old "doit"
                doit    execute it effectivelly instead of print instruction
                diff    do a differential backup
''
select @ret=-1

ret:
return @ret
end -- sp__backup'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__backup:

-- =========================================================== sp__backup_server
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__backup_server',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110726
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__backup_server') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__backup_server') with nowait
        goto skip_sp__backup_server
        end
    if @ver>110726
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__backup_server') with nowait
        goto skip_sp__backup_server
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__backup_server') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__backup_server'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__backup_server]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110726\s.zaglio:modified default name from %db%_%t in %db%
    v:110720\s.zaglio:added @include
    v:110719\s.zaglio:sp__backup_server
    t:sp__backup_server ''c:\backupSQL'',@exclude=''ReportServer$WEBAPP'',@dbg=1
    t:xp_cmdshell ''dir c:\backupSQL''
*/
CREATE proc sp__backup_server
    @path       nvarchar(512) = null,
    @include    nvarchar(4000)= null,
    @exclude    nvarchar(4000)= null,
    @opt        sysname = null,
    @dbg        int = 0
as
begin
-- set nocount on added to prevent extra result sets from
-- interfering with select statements.
set nocount on
-- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg''
declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id
select  @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0)
select  @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')
-- ========================================================= param formal chk ==

-- ============================================================== declaration ==
declare @db sysname,@device nvarchar(1024),@psep nvarchar(32)
create table #exclude ([name] sysname)
create table #include ([name] sysname)

-- =========================================================== initialization ==
select @psep=psep from fn__sym()

insert #exclude([name])
select ''%tempdb%'' union
select ''master'' union
select ''msdb'' union
select ''model'' union
select token from dbo.fn__str_table(@exclude,''|'')

if @include is null
    insert #include([name]) select ''%''
else
    insert #include([name])
    select token from dbo.fn__str_table(@include,''|'')

select db.[name]
into #dbs
-- select db.[name]
from master..sysdatabases db
join #include inc on db.[name] like inc.[name]
left join #exclude ex on db.[name] like ex.[name]
where [status] & (512|4096) = 0
and ex.[name] is null

drop table #exclude
/*
1 = autoclose (ALTER DATABASE)
4 = select into/bulkcopy (ALTER DATABASE tramite SET RECOVERY)
8 = trunc. log on chkpt (ALTER DATABASE tramite SET RECOVERY)
16 = torn page detection (ALTER DATABASE)
32 = loading
64 = pre recovery
128 = recovering
256 = not recovered
512 = offline (ALTER DATABASE)
1024 = read only (ALTER DATABASE)
2048 = dbo use only (ALTER DATABASE tramite SET RESTRICTED_USER)
4096 = single user (ALTER DATABASE)
32768 = emergency mode
4194304 = autoshrink (ALTER DATABASE)
1073741824 = cleanly shutdown
*/

if right(@path,1)!=@psep select @path=@path+@psep

-- ======================================================== second params chk ==
if @path is null goto help

-- ===================================================================== body ==

declare cs cursor local for
    select [name]
    from #dbs
    where 1=1
open cs
while 1=1
    begin
    fetch next from cs into @db
    if @@fetch_status!=0 break

    if charindex(''%db%'',@path)=0 select @device=@path+''%db%''
    if charindex(''.'',@path)=0 select @device=@device+''.bak''

    if @dbg=0
        begin
        exec @ret=sp__backup @device out,@db,@opt=''doit''
        if @ret=0 exec sp__printf ''### %s backed up to "%s" ###'',@db,@device
        end
    else
        exec @ret=sp__backup @device out,@db
    end -- while of cursor
close cs
deallocate cs

goto ret

-- =================================================================== errors ==
-- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret
-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    backup all online and non single user db of this server

Parameters
    @path       is the destination folder
    @include    list of db to include, separated by |. Can use %.
    @exclude    list of db to exclude, separated by |. Can use %.
                (%tempdb% are always excluded)
    @opt        options
                not used
    @dbg        1, show simulation

-- List of DB that will be saved --
''

exec sp__select_astext ''select * from #dbs order by 1''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret

end -- proc sp__backup_server'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__backup_server:

-- ================================================================== sp__checks
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__checks',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=080716
        begin
        if @aut!='S.Zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__checks') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__checks') with nowait
        goto skip_sp__checks
        end
    if @ver>080716
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__checks') with nowait
        goto skip_sp__checks
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__checks') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__checks'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__checks]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:080716\S.Zaglio: disable checks for all tables of optional other db
*/
CREATE PROCEDURE sp__checks
    @action nchar(2)=''-?'',
    @db_dst nvarchar(128)=null
AS
begin
declare @dbg bit
set @dbg=1
if @db_dst is null set @db_dst=db_name()

declare @sql nvarchar(512)
if @action=''-?'' goto usage
if @action=''EA'' -- enable all
    begin
    if @dbg=1 print ''enable all constraint''
    set @sql=''use ''+@db_dst+'' alter table ? CHECK CONSTRAINT ALL ''
    if @dbg=1 exec sp__inject @sql out,''print '''''',''''''''
    exec sp__foreachobj ''TABLE'',@sql
    end
if @action=''DA'' -- disable all
    begin
    if @dbg=1 print ''disable all constraint''
    set @sql=''use ''+@db_dst+'' alter table ? NOCHECK CONSTRAINT ALL ''
    if @dbg=1 exec sp__inject @sql out,''print '''''',''''''''
    exec sp__foreachobj ''TABLE'',@sql
    end
return
usage:
    print ''sp__checks''
    print ''    @action nchar(2)=''''-?''''''
    print ''    @tbl nvarchar(128)=''''%''''''
    print ''    @db_dst nvarchar(128)=null''
    print ''usage:''
    print '' sp_t -? this help''
    print '' sp_t EA enable all triggers''
    print '' sp_t DA disable all triggers''
    return
test:
    exec sp__triggers ''DA'',@tbl=''a%''
end'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__checks:

-- ================================================================ sp__chknulls
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__chknulls',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110210
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__chknulls') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__chknulls') with nowait
        goto skip_sp__chknulls
        end
    if @ver>110210
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__chknulls') with nowait
        goto skip_sp__chknulls
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__chknulls') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__chknulls'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__chknulls]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110210\s.zaglio: added more params
    v:101103\s.zaglio: more explicit sample
    v:080817\S.Zaglio: check if all parameters are nulls (use in params check)
    t:
        declare @r int
        exec @r=sp__chknulls ''a|b|c'',1,null,''a'',@dbg=1
        print @r    -->0
        exec @r=sp__chknulls null,null,null,null,@dbg=1
        print @r    -->1
*/
CREATE proc [dbo].[sp__chknulls]
    @p0 sql_variant=null,
    @p1 sql_variant=null,
    @p2 sql_variant=null,
    @p3 sql_variant=null,
    @p4 sql_variant=null,
    @p5 sql_variant=null,
    @p6 sql_variant=null,
    @p7 sql_variant=null,
    @p8 sql_variant=null,
    @p9 sql_variant=null,
    @dbg bit=0
as
begin
declare @r int
if  @p0 is null and
    @p1 is null and @p2 is null and @p3 is null and
    @p4 is null and @p5 is null and @p6 is null and
    @p7 is null and @p8 is null and @p9 is null
    begin
    set @r=1
    if @dbg=1 print ''all nulls''
    end
else set @r=0
return @r
end -- [sp__chknulls]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__chknulls:

-- ================================================================== sp__circle
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__circle',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120924
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__circle') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__circle') with nowait
        goto skip_sp__circle
        end
    if @ver>120924
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__circle') with nowait
        goto skip_sp__circle
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__circle') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__circle'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__circle]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility,draw
    k:draw,circle,text,buffer
    v:120924\s.zaglio: draw a circle into a text buffer
    t:sp__circle 77
*/
CREATE proc sp__circle
    @r int = null,
    @x int = null,
    @y int = null,
    @buffer nvarchar(max) = null,
    @opt sysname = null,
    @dbg int=0
as
begin
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
set nocount on
-- @@nestlevel is >1 if called by other sp

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    -- error vars
    @e_msg nvarchar(4000),              -- message error
    @e_opt nvarchar(4000),              -- error option
    @e_p1  sql_variant,
    @e_p2  sql_variant,
    @e_p3  sql_variant,
    @e_p4  sql_variant

select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

-- ========================================================= param formal chk ==

-- ============================================================== declaration ==
declare
    -- generic common
    -- @i int,@n int,                      -- index, counter
    -- @sql nvarchar(max),                 -- dynamic sql
    -- options
    -- @opt1 bit,@opt2 bit,
    @i int,@j int,
    @crlf varchar(2),
    @diff int,
    @out bit,
    @end_declare bit

-- =========================================================== initialization ==
select
    -- @opt1=charindex(''|opt|'',@opt),
    @out=case when @buffer is null then 1 else 0 end,
    @buffer=isnull(@buffer,''''),
    @crlf=crlf,
    @end_declare=1
from fn__sym()

-- ======================================================== second params chk ==
if @r is null -- @opt=''||''
    goto help

-- ===================================================================== body ==

select @i=-@r
while @i<=@r
    begin
    select @j=-@r
    while @j<=@r
        begin
        select @diff=round(sqrt(@i*@i+@j*@j)-@r,0)
        select @buffer=@buffer+case @diff when 0 then ''*'' else '' '' end+'' ''
        select @j=@j+1
        end -- j
    select @buffer=@buffer+@crlf,@i=@i+1
    end -- i

if @out=1 exec sp__printsql @buffer

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.

goto ret

-- =================================================================== errors ==
/*
err:        exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3,
                              @p4=@e_p4,@opt=@e_opt                     goto ret

err_me1:    select @e_msg=''write here msg''                              goto err
err_me2:    select @e_msg=''write this %s'',@e_p1=@var                    goto err
*/
-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    draw a circle into buffer or video

Parameters
    @r      radius
    @x,@y   center (TODO)
    @buffer predefined @buffer
    @opt    options (not used)

Examples
    exec sp__circle 7
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret

end -- proc sp__circle'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__circle:

-- ================================================================= sp__comment
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__comment',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100328.1000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__comment') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__comment') with nowait
        goto skip_sp__comment
        end
    if @ver>100328.1000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__comment') with nowait
        goto skip_sp__comment
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__comment') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__comment'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__comment]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100328.1000\s.zaglio: support of proc,func,view...
    v:100321\s.zaglio: support for quoted table name
    v:100228\s.zaglio: added more help
    v:100219\s.zaglio: now print if @comment is null and delete if is '''';+help
    v:100129\s.zaglio: creation
    todo: using MS original methos is slow. Need to be rewritten
    t:
        create table test(t1 int,t2 int)
        exec sp__printf ''print comment of test''
        exec sp__comment ''test''
        exec sp__printf ''set comment of test''
        exec sp__comment ''test'',''test comment''
        exec sp__printf ''print comment of test''
        exec sp__comment ''test''
        exec sp__printf ''delete comment of test''
        exec sp__comment ''test'',''''  -- delete comment
        exec sp__printf ''print comment of test''
        exec sp__comment ''test''

        exec sp__comment ''[test]'',''test comment on table''
        exec sp__comment ''test.t1'',''test comment on t1'',@dbg=1
        exec sp__comment ''test.t2'',''test comment on t2''
        print dbo.fn__comment(''test'')
        select * from dbo.fn__comments(''test'')
        drop table test
    t:
        exec sp__comment ''sp__comment'',''test of sp comment'',@dbg=1
        exec sp__comment ''sp__comment.@path'',''name of object to comment'',@dbg=1
        print dbo.fn__comment(''sp__comment.@path'')
        exec sp__comment ''fn__comment.@path'',''name of object to comment'',@dbg=1
        print dbo.fn__comment(''fn__comment.@path'')

        select * from dbo.fn__comments(''sp__comment'')
*/
CREATE proc [dbo].[sp__comment]
    @path sysname=null,
    @comment nvarchar(4000)=null out,
    @dbg bit=0
as
begin
set nocount on
declare
    @proc sysname,
    @schema sysname,@sch_type sysname,
    @obj sysname,@obj_type sysname,
    @sub sysname,@sub_type sysname,
    @old_comment nvarchar(4000),
    @msg nvarchar(4000),@id int,
    @prop sysname,@xtype nvarchar(2)

select @proc=''sp__comment''

if @obj is null and @comment is null goto help

select @prop=prop,@schema=sch,@sch_type=sch_type,
       @obj_type=obj_type,@obj=obj,
       @sub_type=sub_type,@sub=sub
from dbo.fn__comment_types(@path)

if @dbg=1
    begin
    exec sp__printf ''prp=%s, sc=%s, tbl=%s, col=%s, @xt=%s, @id=%d'',
                    @prop,@schema,@obj,@sub,@xtype,@id
    exec sp__printf ''\t\t\t\tsct=%s, ttbl=%s, tcol=%s'',
                    @sch_type,@obj_type,@sub_type
    end

select @old_comment=convert(nvarchar(4000),value )
from fn_listextendedproperty (
    @prop,
    @sch_type, @schema,
    @obj_type, @obj,
    @sub_type, @sub);

if @comment is null begin select @comment=@old_comment exec sp__printf @old_comment goto ret end

if @comment=''''
    begin
    select @comment=@old_comment
    if not @comment is null
        begin
        exec sp__printf ''-- deleting comment "%s" for obj "%s"'',@comment,@obj
        exec sp_dropextendedproperty
            @name = @prop,
            @level0type = @sch_type, @level0name = @schema,
            @level1type = @obj_type, @level1name = @obj,
            @level2type = @sub_type, @level2name = @sub
        end
    goto ret
    end

if @old_comment is null
    exec sp_addextendedproperty
        @name = @prop, @value = @comment,
        @level0type = @sch_type, @level0name = @schema,
        @level1type = @obj_type, @level1name = @obj,
        @level2type = @sub_type, @level2name = @sub
else
    begin
    if @dbg=1 exec sp__printf ''-- replace comment "%s" of "%s"'',@old_comment,@obj
    exec sp_updateextendedproperty
        @name = @prop, @value = @comment,
        @level0type = @sch_type, @level0name = @schema,
        @level1type = @obj_type, @level1name = @obj,
        @level2type = @sub_type, @level2name = @sub
    end

goto ret

help:
select @msg =''Usage\n''
            +''\t@obj    can be table; table.column;(no sp,fn,view)''
exec sp__usage @proc,''
Parameters
    @obj    can be table; table.column;(no sp,fn,view)

Examples
    exec sp__comment ''''table'''',''''comment for table''''        -- se comment on table
    exec sp__comment ''''table.col'''',''''comment for column''''   -- se comment on column of table
    exec sp__comment ''''table'''',''''new comment''''              -- change comment
    exec sp__comment ''''table''''                              -- print comment
    exec sp__comment ''''table'''',''''''''                         -- remove comment

See also
    sp__into_tbl @tbl       show columns info of a table with comments

Note
    Actually is not possible get/set comments on view/proc/func
''

ret:
end -- proc sp__comment'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__comment:

-- ============================================================ sp__context_info
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__context_info',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120724
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__context_info') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__context_info') with nowait
        goto skip_sp__context_info
        end
    if @ver>120724
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__context_info') with nowait
        goto skip_sp__context_info
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__context_info') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__context_info'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__context_info]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:120724\s.zaglio:changed structure
    v:111205\s.zaglio:set and reset context info
    t:sp__context_info @opt=''reset''
    t:sp__context_info ''test'',@dbg=1    -- d15f
    t:sp__context_info ''test1'',@dbg=1   -- 5310
    t:sp__context_info ''test'',@opt=''del'',@dbg=1
    t:select dbo.fn__context_info(''test''),dbo.fn__context_info(''test1'')
    t:select dbo.fn__context_info(''test2'')
*/
CREATE proc sp__context_info
    @val sysname = null,
    @opt sysname = null,
    @dbg int=0
as
begin
-- set nocount on added to prevent extra result sets from
-- interfering with select statements.
set nocount on
-- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg''
declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id
select  @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0)
select  @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')
-- ========================================================= param formal chk ==
if @val is null and @opt=''||'' goto help

-- ============================================================== declaration ==
declare
    @i      int,
    @l      int,
    @j      int,                        --
    @info   varchar(256),
    @cinfo  varbinary(128),
    @code   binary(2),@tcode binary(2), -- temporary code
    @del    bit                         -- del option
-- =========================================================== initialization ==
select
    @cinfo= isnull(context_info(),0),
    @del  = charindex(''|del|'',@opt),
    @code = dbo.fn__crc16(@val)

-- ======================================================== second params chk ==
if charindex(''|reset|'',@opt)>0
    begin
    select @cinfo=0
    set context_info @cinfo
    goto ret
    end

-- ===================================================================== body ==
-- scan cinfo and add or delete
select @i=1,@l=len(@cinfo),@j=0
while (@i<@l)
    begin
    if @j=0 and substring(@cinfo,@i,2)=0 select @j=@i
    if substring(@cinfo,@i,2)=@code break
    select @i=@i+2
    end

if @del=1 select @code=0
if @i<@l select @j=@i
select @cinfo=substring(@cinfo,1,@j-1)+@code+substring(@cinfo,@j+2,128)
set context_info @cinfo
if @dbg>0 print dbo.fn__hex(@cinfo)

dispose:
goto ret

-- =================================================================== errors ==
err_len:    exec @ret=sp__err ''context info is full'',@proc
            goto ret
-- ===================================================================== help ==
help:
select @info=dbo.fn__hex(context_info())

exec sp__usage @proc,''
Scope
    add or remove value to the process context info

Notes
    fn__context_info return the position if exists of zero.
    The position remain until somebody not delete and reinsert the value.

Parameters
    @val    string to codify and add to context info
    @opt    options
            del     remove the @val from context info
            reset   clean all context info

Examples
    exec sp__context_info "test"
    print dbo.fn__context_info("test")

-- Corrent context info is --
%p1%
'',@p1=@info
select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret

end -- proc sp__context_info'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__context_info:

-- ==================================================================== sp__copy
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__copy',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100203
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__copy') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__copy') with nowait
        goto skip_sp__copy
        end
    if @ver>100203
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__copy') with nowait
        goto skip_sp__copy
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__copy') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__copy'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__copy]

begin try
exec dbo.sp_executesql @statement = N'/*  keep this for MS compatibility
    l:see LICENSE file
    g:utility
    v:100203\s.zaglio:  added -t in bcp call coz'' sql2k5 compatibility
    v:100202\s.zaglio:  added quotes and removed -t,-q in bcp call coz'' sql2k5 compatibility
    v:100111\s.zaglio:  a bug around local obj search
    v:091212\s.zaglio:  a different error report for bcp
    v:091209\s.zaglio:  added supporto for ## tables on bcp copy
    v:091206\s.zaglio:  added trust connection on bcp copy and specific error info on user rights
    v:091018\s.zaglio:  well tested version with bcp
    r:091015\s.zaglio:  added BCP extension. if @src/dsc end with .txt or .cvs is a file
    v:090812\s.zaglio:  global revision
    v:090713\S.Zaglio:  added fast restore from table_date_time to table
                        (disable triggers,not manage quoted names)
    v:090405\s.Zaglio:  revision
    v:090124\S.Zaglio:  create a local copy of a table (if @obj only specified) or copy to remote server
    t:sp__copy ''test'',@dbg=1      -- backup
    t:sp__copy ''test'',@b=1,@dbg=1 -- restore
    t:sp__copy ''ot04_stock'',''ot04_stock_uni'',@u=1,@v=2,@d=0,@uid=''sa'',@pwd='''',@dbg=1
    t:sp__copy_test_bcp
    t:
        create table test(id int identity,obj sysname)
        insert test select ''one''
        insert test select ''two''
        exec sp__copy ''test''
        drop table test
        drop table test_100111_1805
*/
CREATE proc [sp__copy]
    @src        sysname=null,       -- local obj  ( can accept wild chars as * & ?)
    @dst        sysname=null out,   -- duplicated obj or db or db.schema.obj or lnk.db or
    @r          bit=0,              -- restore from last backup (search for obj_date_time)
    @s          bit=0,              -- structure only
    @d          bit=1,              -- drop destination
    @t          bit=0,              -- enable trigger while copy
    @u          bit=0,              -- transform to unicode
    @v          tinyint=0,          -- activate verbose mode: 1=src->dst 2=more steps
    @uid        sysname=null,       -- necessary for recompiling on remote svr
    @pwd        sysname=null,       -- or on local server if we want a file compile
    @soe        bit=0,              -- stop on error
    @dbg        bit=0
as
begin
-- sp_find ''sp__copy'' -- used in:sp__copyalldata_to_db,sp__create_test_db,sp__distribute,sp_copy,sp_sync_distribute,sp_trk_adjust,sp_update_dev_data
/*  after hard work, ofcourse thanks to MS politics, something go wrong. SQLDMO will be dimessed
    and in a cluster of my customer some library was badly registered.
    So I decided to downgrade this sp to more standard form even if loose performance and backward compatibility

    sp__copy -> sp__script -> tmp table -> linked server -> sp__run_script -> drop local & remote tmp table
*/
set nocount on
declare
    @proc sysname,
    @msg nvarchar(4000),@tmp nvarchar(4000),@ret int,@line nvarchar(4000),
    @crlf nvarchar(2),@i int,@n int,@j int,@step int,
    @obj sysname,@obj_to sysname,
    @dt datetime,
    @bak sysname,
    @srv sysname,@db sysname,@schema sysname,@name sysname,
    @sql nvarchar(4000),@sql1 nvarchar(4000),@sql2 nvarchar(4000),@sql3 nvarchar(4000),
    @srv_sql nvarchar(512),@copy_sql nvarchar(512),
    @ot sysname,                    -- object type
    @oc_tbl smallint,   @oc_dri smallint,   @oc_trg smallint,
    @dbgdev bit,
    @ctofile bit,                   -- compile to file
    @srv_cur sysname,
    @db_cur sysname,
    @bcp_cmd nvarchar(1024),@bcp_op nvarchar(4),@file sysname,
    @temp nvarchar(512),
    @stype nvarchar(2),@dtype nvarchar(2),@ctype nvarchar(8),
    @exp1 bit,@exp2 bit,
    @end_declare bit

declare @objs table (id int identity,name sysname, type nchar(2))
declare @objd table (id int identity,name sysname, type nchar(2))

-- init and adjust
select
    @proc=''sp__copy'',
    @ret=0,
    @crlf=char(13)+char(10),
    @step=10,
    @oc_tbl=1,   -- table with owner and not chk
    @oc_dri=20,  -- pkey,idx and chk
    @oc_trg=32,  -- triggers only
    @dbgdev=0,
    @srv_cur=@@servername,
    @db_cur=db_name(),
    @end_declare=0

if not (@uid is null and @pwd is null)
    begin
    select @ctofile=1
    if @dbg=1 exec sp__printf ''-- will be compiled with osql''
    end

-- help
if @src is null goto help

if @dbg=1 exec sp__printf ''sp__copy @src=%s, @dst=%s'',@src,@dst

-- collect objects to copy
if charindex(''*'',@src)>0 or charindex(''?'',@src)>0
    insert into @objs (name,type)
    select name,xtype from sysobjects where name like replace(replace(replace(@src,''_'',''[_]''),''?'',''_''),''*'',''%'')
if charindex(''*'',@dst)>0 or charindex(''?'',@dst)>0
    insert into @objd (name,type)
    select name,xtype from sysobjects where name like replace(replace(replace(@dst,''_'',''[_]''),''?'',''_''),''*'',''%'')

select @exp1=0,@exp2=0
if right(@src,4) in (''.txt'',''.cvs'') or charindex(''\'',@src)>0 select @exp1=1
if right(@dst,4) in (''.txt'',''.cvs'') or charindex(''\'',@dst)>0 select @exp2=1

if @exp1=1 and @exp2=0
    begin
    if @dbg=1 exec sp__printf ''source is a file''
    insert @objs (name,type) select @src,''FL''
    if left(@dst,2)=''##''
        insert @objd (name,type) select @dst,''U''
    else
        insert @objd (name,type) select name,xtype from sysobjects where name=@dst
    if left(@dst,1)=''#'' and left(@dst,2)!=''##'' goto err_bcpnotmp
    end
if @exp1=0 and @exp2=1
    begin
    if @dbg=1 exec sp__printf ''destination is a file''
    if left(@src,1)=''#'' and left(@src,2)!=''##'' goto err_bcpnotmp
    if left(@src,2)=''##''
        insert @objs (name,type) select @src,''U''
    else
        insert @objs (name,type) select name,xtype from sysobjects where name=@src
    insert @objd (name,type) select @dst,''FL''
    end

-- local copy
if @exp1=0 and @exp2=0
    begin
    insert @objs (name,type) select name,xtype from sysobjects where name=@src
    insert @objd (name,type) select name,xtype from sysobjects where name=@src
    end

if @dbg=1 select * from @objs s left join @objd d on s.id=d.id

if not exists(select null from @objs) goto err_noobjs


create table #src (lno int identity(10,10),line nvarchar(4000))

-- for each @obj int @objs
select @i=min(id),@n=max(id) from @objs
while (@i<=@n) and (@ret=0 or @soe=0)
    begin
    select @obj=s.name,@stype=s.type,@obj_to=d.name,@dtype=d.type
    from @objs s left join @objd d on s.id=d.id where s.id=@i

    if @obj is null goto err_objnull
    if @obj_to is null goto err_bcpnotbl

    select @i=@i+1
    select @ot=dbo.fn__object_type(@obj)

    select @ctype=case
        when @stype=''FL'' and @dtype in (''U'')    then ''bcp<''
        when @stype in (''U'') and @dtype=''FL''    then ''bcp>''
        when @dst is null and @r=0              then ''bak''
        when @dst is null and @r=1              then ''res''
        else null
        end

    if @ctype is null goto err_ctype

    if @dbg=1 exec sp__printf ''sp__copy:@n=%d, @i=%d,@obj=%s,@obj_to=%s,@ctype=%s'',@n,@i,@obj,@obj_to,@ctype

    if @ctype in (''bcp>'',''bcp<'')
        begin
        -- if @db=''%db%'' or @svr=''%svr%''
        select
            @db=@db_cur,@srv=@srv_cur
            -- 091206: ,@uid=coalesce(@uid,''sa''),@pwd=coalesce(@pwd,'''')
        if @ctype=''bcp>'' select @bcp_op=''out'',@file=@obj_to,@obj=@obj
        else select @bcp_op=''in'',@file=@obj,@obj=@obj_to
        select @j=dbo.fn__charindex(''\'',@file,-1)
        if @j>0 select @temp=substring(@file,1,@j-1),@file=substring(@file,@j+1,4000)
        if @j=0 or @temp=''%temp%'' exec sp__get_temp_dir @temp out

        select
            @file=@temp+''\''+@file,
            @obj=case when left(@obj,1)=''#'' then @obj else @db+''..''+@obj end
        -- /t use space as terminator
        -- /n use native varchar
        -- /q SET QUOTED_IDENTIFIERS ON
        -- -C { ACP | OEM | RAW | code_page }
        -- -T (in upper case) trusted connection
        if @uid is null and @pwd is null
            select @bcp_cmd=''bcp "%db_table%" %op% "%file%" -S "%svr%" -c -T -CACP -t''
        else
            select @bcp_cmd=''bcp "%db_table%" %op% "%file%" -S "%svr%" -U "%uid%" -P "%pwd%" -c -CACP -t''
        exec sp__str_replace @bcp_cmd out,''%db_table%|%op%|%file%|%svr%|%uid%|%pwd%'',
                                          @obj,@bcp_op,@file,@srv,@uid,@pwd
        if @dbg=1 exec sp__printf @bcp_cmd
        insert into #src(line)
        exec @r=master..xp_cmdshell @bcp_cmd
        if @r=0 and exists(select null from #src where line like ''Error = %'') select @r=1
        if @r!=0
            begin
            exec sp__print_table ''#src''
            exec sp__printf @bcp_cmd
            goto err_bcp
            end
        continue
        end -- bcp

    -- backup/restore
    if @ctype in (''bak'',''res'')
        begin
        if @ctype=''res''
            begin
            select top 1 @bak=name
            from sysobjects
            where name like @obj+''[_]______[_]____''
            and isnumeric(right(name,4))=1
            and isnumeric(substring(name,len(name)-10,6))=1
            order by substring(name,len(name)-10,128) desc
            if @bak is null
                begin
                exec sp__printf ''-- no %s_yymmdd_hhnn found'',@obj
                continue
                end
            -- if found a table
            exec sp__printf ''-- restore %s -> %s '',@bak,@obj
            select @sql =''exec sp__triggers ''''da'''',''''''+@obj+'''''' ''+@crlf
                        +''truncate table ''+@obj+'' ''+@crlf
                        +''set identity_insert ''+@obj+'' on''+@crlf
                        +''insert into ''+@obj+'' select * from ''+@bak+'' ''+@crlf
                        +''set identity_insert ''+@obj+'' off''+@crlf
                        +''exec sp__triggers ''''ea'''',''''''+@obj+''''''''
            if @dbg=1 print @sql else exec (@sql)
            if @@error!=0 select @ret=1
            continue    -- next object
            end -- if @b=1

        -- backup mode
        set @dst=@obj+''_%t''
        set @dt=getdate()
        set @dst=replace(@dst,''%t'',convert(nvarchar(48),@dt,12)+''_''
                +right(''00''+convert(nvarchar(2),datepart(hh,@dt)),2)
                +right(''00''+convert(nvarchar(2),datepart(mi,@dt)),2))
        set @obj=dbo.fn__sql_quotename(@obj)
        set @dst=dbo.fn__sql_quotename(@dst)
        exec sp__printf ''-- copy %s -> %s '',@obj,@dst
        set @sql=''select * into ''+@dst+'' from ''+@obj+'' with (nolock) ''
        if @dbg=1 print @sql else exec(@sql)
        if @@error!=0 select @ret=1
        continue
        end -- backup mode

    -- copy mode
    if @v>0 exec sp__printf ''-- copy %s -> %s '',@obj,@dst

    /*
        1: parse names to determinate the form
        2: create the script of the source without trigger & index
            or with trigger&index if @t=1
        3: if @d=1 drop target
        4: rename or export structure
        5: if (only struct)@s=0 continue with next obj
        6: else copy data
    */
    exec sp__parse_name @dst,@srv out,@db out,@schema out,@name out
    if @srv=@@servername or @srv=dbo.fn__servername(null) select @srv=null
    if not @srv is null     -- check if remote (linked) svr exists
        begin
        if not exists (select * from master..sysservers where srvname=@srv and rpc=1)
            goto err_srv_or_rpc

        if @db is null select @db=db_name()
        -- check id remote db exists
        select @sql=''select @j=count(*) from ''+@srv+''.master..sysdatabases where name=''''''+@db+''''''''
        exec sp_executesql @sql,N''@n int out'',@j=@j
        if @j!=1 goto err_srv_db

        -- todo: check remote schema
        end

    -- if exist a db with same name of obj, the db win
    if  @srv is null and @db is null
    and exists (select * from master..sysdatabases where name=@name) select @db=@name,@name=null

    -- check locl db existance
    if  @srv is null and not @db is null
    and not exists (select * from master..sysdatabases where name=@db) goto err_loc_db

    -- todo: check local schema

    -- drop detination
    if @d=1
        begin
        if @dbg=1 exec sp__printf ''-- drop destination\nexec sp__drop ''''%s'''''',@name
        -- more secure check
        if @obj=@name goto err_same
        if @srv is null and @dbg=0 exec sp__drop @name
        if not @srv is null goto err_nods   -- todo
        end
    else
        begin
        if @obj=@name goto err_same
        if (@srv is null and @db is null) begin
            if dbo.fn__exists(@name,null)=1 goto err_dstexist
            end
        else
            goto err_dstchk
        end -- if @d=...

    -- create script
    if @dbg=1 exec sp__printf ''-- get script source''

    if @t=0
        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_tbl  -- script without idx and trigger
    else
        begin
        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_tbl
        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_dri
        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_trg
        end

    if @name!=@obj
        begin
        if @dbg=1 exec sp__printf ''-- rename''
        exec sp__script_replace @obj,@name,@step=@step              -- rename indexes, trigger...
        end

    if @dbgdev=1 select * from #src order by lno

    -- to unicode
    if @u=1
        begin
        if @dbg=1 exec sp__printf ''-- convert to unicode''
        exec sp__script_reduce @normalize=4
        end

    -- add change of db
    if not @db is null
        begin
        if @dbg=1 exec sp__printf ''-- add change of db''
        set identity_insert #src on
        insert into #src(lno,line) select 5,''use ''+@db
        set identity_insert #src off
        end

    -- if remote server, transfer src to dst server
    if not @srv is null
        begin
        select @srv_sql =''exec %srv%.%db%.%dbo%.sp_executesql ''
        exec sp__str_replace @srv_sql out,''%srv%|%db%|%dbo%|%tmp%'',@srv,@db,@schema,@tmp
        select @tmp=''tmp_''+replace(convert(sysname,newid()),''-'',''_'')
        select @sql =@srv_sql+
                    +''N''''create table %tmp% (lno int ,line nvarchar(4000))'''' ''
                    +''insert into %srv%.%db%.%dbo%.%tmp% select * from #src''
        exec sp__str_replace @sql out,''%srv%|%db%|%dbo%|%tmp%'',@srv,@db,@schema,@tmp
        if @dbg=1 print @sql else exec(@sql)
        end

    -- compile
    if @dbg=1
        exec sp__script ''#src''
    else
        begin
        exec @ret=sp__recompile ''#src'',
            @tofile=@ctofile,
            @srv=@srv_cur,
            @db=@db_cur,
            @uid=@uid,@pwd=@pwd
            -- ,@dbg=1
        if @ret!=0 goto err_comptbl
        end

    -- prepare sql for copy
    select @copy_sql    =''insert into ''
                        + case when not @srv is null
                          then ''%srv%.'' else '''' end
                        + case when not @db is null
                          then ''%db%.'' else '''' end
                        + case when not @schema is null
                          then ''%schema%.'' else '''' end
                        +''%name% ''
                        +''select * from %obj%''

    if @db is null select @sql=replace(@copy_sql,''%db%.'','''')
    exec sp__str_replace @copy_sql out,''%srv%|%db%|%schema%|%name%|%obj%'',@srv,@db,@schema,@name,@obj

    -- if is a table, load and run index and trigger
    if @ot=''U''
        begin
        -- if not structure only and not trigger while copy, copy data now
        if @s=0 and @t=0
            begin
            if @dbg=1 exec sp__printf ''-- copy data without idx and trg''
            if @dbg=1
                print @copy_sql
            else
                begin
                if @v>1 exec sp__printf ''-- coping data ...''
                exec(@copy_sql)
                end
            end

        if @dbg=1 exec sp__printf ''-- add idx and trg''

        truncate table #src
        if @dbgdev=1 select * from #src order by lno

        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_dri
        exec sp__script @obj,''#src'',@step=@step,@oc=@oc_trg
        if @name!=@obj exec sp__script_replace @obj,@name,@step=@step

        if @u=1 exec sp__script_reduce @normalize=4     -- to unicode
        if @dbg=1
            exec sp__script ''#src''
        else
            begin
            exec @ret=sp__recompile ''#src'',
                @tofile=@ctofile,
                @srv=@srv_cur,
                @db=@db_cur,
                @uid=@uid,@pwd=@pwd
                -- ,@dbg=1
            if @ret!=0 goto err_compdri
            end

        -- finally copy data if with trigger on
        if @s=0 and @t=1
            begin
            if @dbg=1 print @copy_sql else
                begin
                if @v>1 exec sp__printf ''-- coping data ...''
                exec(@copy_sql)
                end
            end

        end -- if ot=''U''


    end -- while


drop table #src
goto ret

err_noobjs:     select @ret=-1 ,@msg=''#!no object found with this name/s'' goto ret
err_srv_or_rpc: select @ret=-2 ,@msg=''#!no dst server found or not support rpc'' goto ret
err_srv_db:     select @ret=-3 ,@msg=''#!no dst db found'' goto ret
err_loc_db:     select @ret=-4 ,@msg=''#!no local db found'' goto ret
err_nofc:       select @ret=-6 ,@msg=''#!file''''s compile not supported again'' goto ret
err_nods:       select @ret=-7 ,@msg=''#!remote drop not supported again'' goto ret
err_same:       select @ret=-8 ,@msg=''#!cannot copy on itself'' goto ret
err_dstexist:   select @ret=-9 ,@msg=''#!destination already exists, use @d=1'' goto ret
err_dstchk:     select @ret=-10,@msg=''#!remote destination existance not yet implemented'' goto ret
err_comptbl:    select @ret=-11,@msg=''#!compiling table'' goto ret
err_compdri:    select @ret=-12,@msg=''#!compiling dri'' goto ret
err_ctype:      select @ret=-13,@msg=''#!unk ctype'' goto ret
err_objnull:    select @ret=-14,@msg=''#!null object name'' goto ret
err_bcp:        select @ret=-15,@msg=''#!bcp has returned an error(NB: "unexpected EOF/Fine imprevista",''
                                    +''may depends on user''''s rights in trusted(-T) connection)'' goto ret
err_bcpnotbl:   select @ret=-16,@msg=''#!bcp require an existing dest. table'' goto ret
err_bcpnotmp:   select @ret=-17,@msg=''#!bcp cannot support temp tables'' goto ret

help:
select @msg =''Copy/rename a db object with or without data between dbs of linked servers\n''+
            +''Parameters:\n''
            +''\t@src    name of source object of local db\n''
            +''\t@dst    newname of local duplicate or db or svr.db or db.schema.name or\n''
            +''\t        svr.db.schema.newname\n''
            +''\nExamples\n''
            +''\tsp__copy ''''mytable'''',''''mytable.txt''''\t-- bcp to %temp%dir\file\n''
            +''\tsp__copy ''''c:\test\mytable.txt'''',''''mytable.txt''''\t-- bcp fromo file''

exec sp__usage @proc,@extra=@msg

ret:
if not @msg is null exec sp__printf @msg
return @ret
end -- proc'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__copy:

-- =============================================================== sp__copy_data
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__copy_data',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100517
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__copy_data') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__copy_data') with nowait
        goto skip_sp__copy_data
        end
    if @ver>100517
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__copy_data') with nowait
        goto skip_sp__copy_data
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__copy_data') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__copy_data'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__copy_data]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    g:utility
    v:100517\s.zaglio: changed @objs to #objs
    r:100513\s.zaglio: copy data from specular table of different databases
    todo:integrate into sp__copy)
    todo:now dtbls=stbls
*/
CREATE proc sp__copy_data
    @src sysname=null,
    @dst sysname=null,
    @truncate bit=0,
    @dbg bit=0
as
begin
set nocount on
declare @proc sysname,@ret int
select @proc=''sp_copy_data'',@ret=0
if @src is null and @dst is null goto help

declare
    @sdb sysname,@ssch sysname,@stbl sysname,
    @ddb sysname,@dsch sysname,@dtbl sysname,
    @dflds nvarchar(4000), @sflds nvarchar(4000),
    @sql nvarchar(4000),@i int,@n int,
    @like sysname,
    @end_declare bit

create table #objs (id int identity,src sysname,dst sysname)

select @sdb=db,@ssch=sch,@stbl=obj from dbo.fn__parsename(@src,1,default)
select @ddb=db,@dsch=sch,@dtbl=obj from dbo.fn__parsename(@dst,1,default)

if charindex(''.'',@src)>0 and @sdb=@ddb goto err_pat

if charindex(''*'',@src)=0 insert #objs select @src,@dst
else
    begin
    -- select @sdb,@ssch,@stbl,@ddb,@dsch,@dtbl
    select @like=replace(dbo.fn__sql_unquotename(@stbl),''*'',''%'')
    select @sql=''
        use %sdb%
        insert #objs
        select "%sdb%"+"."+"%ssch%"+"."+[name],"%ddb%"+"."+"%dsch%"+"."+[name]
        from sysobjects
        where [name] like "%like%"
        and xtype="u"
    ''
    exec sp__str_replace @sql out,
        ''"|%sdb%|%ssch%|%ddb%|%dsch%|%like%'',
        '''''''',@sdb,@ssch,@ddb,@dsch,@like
    if @dbg=1 exec sp__printf ''%s'',@sql
    exec(@sql)
    end -- collect objs

create table #vars (id nvarchar(16),value sql_variant)
select @i=min(id),@n=max(id) from #objs

while (@i<=@n)
    begin
    select @src=src,@dst=dst from #objs where id=@i

    select @sdb=db,@ssch=sch,@stbl=obj from dbo.fn__parsename(@src,1,default)
    select @ddb=db,@dsch=sch,@dtbl=obj from dbo.fn__parsename(@dst,1,default)

    select @sflds=dbo.fn__flds_quotename(dbo.fn__flds_of(@stbl,'','',null),'','')
    select @dflds=dbo.fn__flds_quotename(@sflds,'','')

    truncate table #vars
    insert #vars values(''"'',        '''''''')
    insert #vars values(''%sdb%'',    @sdb)
    insert #vars values(''%ssch%'',   @ssch)
    insert #vars values(''%stbl%'',   @stbl)
    insert #vars values(''%ddb%'',    @ddb)
    insert #vars values(''%dsch%'',   @dsch)
    insert #vars values(''%dtbl%'',   @dtbl)
    insert #vars values(''%sflds%'',  @sflds)
    insert #vars values(''%dflds%'',  @dflds)
    if @truncate=1 insert #vars values(''%truncate%'', ''truncate table ''+@dsch+''.''+@dtbl)
    else insert #vars values(''%truncate%'','''')

    select @sql=''
    use %ddb%
    if objectproperty(object_id("%dsch%.%dtbl%"),"tablehasidentity")=1
        set identity_insert %dtbl% on
    %truncate%
    declare @rows bigint
    insert into %dsch%.%dtbl%(%dflds%)
    select %sflds%
    from %sdb%.%ssch%.%stbl%
    select @rows=@@rowcount
    exec sp__printf "-- %dtbl%:%d inserted",@rows
    if objectproperty(object_id("%dsch%.%dtbl%"),"tablehasidentity")=1
        set identity_insert %dtbl% off
    ''
    exec sp__str_replace @sql out,@tbl=1

    if @dbg=1 exec sp__printf ''%s'',@sql
    else exec(@sql)
    if @@error!=0 exec sp__printf ''%s'',@sql

    select @i=@i+1
    end -- while

drop table #vars

goto ret

err_pat:    exec @ret=sp__err ''I see a ''''.'''' but source and dest db are same; maybe forgot schema?'',@proc goto ret

help:
exec sp__usage ''sp__copy_data'',''
Parameters
    @src        source path with database.schema.tables (accept wildcard * on object)
    @dst        destination path with database (names are sames)
    @truncate   truncate dest table
    @dbg        show script but not execute

Examples
    sp__copy_data ''''source_db.dbo.obj'''',''''dest_db'''',@dbg=1,@truncate=1
    sp__copy_data ''''source_db.dbo.obj*'''',''''dest_db'''',@truncate=1,@dbg=1
    sp__copy_data ''''source_db..obj*'''',''''dest_db'''',@truncate=1,@dbg=1
''

select @ret=-1

ret:
return @ret
end -- sp__copy_data'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__copy_data:

-- ================================================================= sp__copy_db
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__copy_db',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120612
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__copy_db') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__copy_db') with nowait
        goto skip_sp__copy_db
        end
    if @ver>120612
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__copy_db') with nowait
        goto skip_sp__copy_db
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__copy_db') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__copy_db'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__copy_db]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:120612\s.zaglio: added errors test and run option
    v:110324\s.zaglio: modern version
    v:100119\s.zaglio: do a backup and restore together
    t:sp__copy_db ''test'',@opt=''tmp:d:\'',@dbg=1
*/
CREATE proc sp__copy_db
    @to sysname=null,
    @from sysname=null,
    @opt sysname=1,
    @dbg bit=0
as
begin
declare @proc sysname,@ret int
select  @proc=object_name(@@procid),@ret=0,
        @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

declare @i int,@j int,@dev nvarchar(1024),@t datetime,@simul bit

if @to is null goto help
if @from is null select @from=db_name()

select @opt=replace(@opt,''|run|'',''|doit|'')   -- compatible with old ver.
select @dev=''%temp%''
select @i=charindex(''|tmp:'',@opt)+5,@j=charindex(''|'',@opt,@i)
if @dbg=1 exec sp__printf ''@opt=%s i=%d, j=%d'',@opt,@i,@j
if @i>5
    select @dev =substring(@opt,@i,@j-@i)
                +''%db%_%t%.bak''

if @dbg=1 exec sp__printf ''dev=%s'',@dev

exec sp__elapsed @t out,''init''
exec @ret=sp__backup @dev out,@from,@opt=@opt
if @ret=0
    begin
    exec sp__elapsed @t out,''after backup''
    exec sp__restore @to,@dev,@opt=@opt
    exec sp__elapsed @t out,''after restore''
    end

goto ret

-- ===================================================================== help ==

help:
exec sp__usage @proc,''
Scope
    duplicate a database into same server

Parameters
    @to     destination name (if not exists, will be created)
    @from   source db; if not specified current is used
    @opt    options
            run     secure code, disable default simulation
            tmp:??  uses ?? as alternative path that has more
                    free disk space

Examples
    sp__copy_db ''''test'''' -- copy this db to TEST db
''
select @ret=-1

ret:
return @ret
end -- sp__copy_db'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__copy_db:

-- =========================================================== sp__copy_test_bcp
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__copy_test_bcp',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=091018
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__copy_test_bcp') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__copy_test_bcp') with nowait
        goto skip_sp__copy_test_bcp
        end
    if @ver>091018
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__copy_test_bcp') with nowait
        goto skip_sp__copy_test_bcp
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__copy_test_bcp') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__copy_test_bcp'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__copy_test_bcp]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:091018\s.zaglio: test for bcp form of sp__copy
*/
CREATE proc sp__copy_test_bcp @dbg bit=0
as
begin
set nocount on
declare @r int
if dbo.fn__exists(''bcp_test'',null)=1 drop table bcp_test
declare @t sysname select @t=''a11_um''
-- sp__dir ''a11_um''
-- select * from a11_um
exec(''select top 0 * into bcp_test from ''+@t)
-- bcp do not manage difference between table and file without format
-- exec(''alter table bcp_test add ok bit'')
if @dbg=1 exec(''select * from ''+@t)
exec @r=sp__copy @t,''bcp_test.txt'',@dbg=1
if @r!=0 goto err
exec @r=sp__run_cmd ''type %temp%\bcp_test.txt''
if @r!=0 goto err
exec @r=sp__copy ''bcp_test.txt'',''bcp_testone'',@dbg=1
if @r!=-16 goto err
exec @r=sp__copy ''bcp_test.txt'',''bcp_test'',@dbg=1
if @r!=0 goto err

select * from bcp_test
drop table bcp_test
goto ret
err:
exec sp__printf ''sp__copy_test_bpc:bcp test error''
ret:
end -- proc'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__copy_test_bcp:

-- =================================================================== sp__count
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__count',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=111214
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__count') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__count') with nowait
        goto skip_sp__count
        end
    if @ver>111214
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__count') with nowait
        goto skip_sp__count
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__count') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__count'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__count]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:111214\s.zaglio: now @tables can use wild chars and restyled
    v:100221\s.zaglio: added @where
    v:091023\s.zaglio: added help
    v:090205\S.Zaglio: a little remake to better manage remote svr/db
    v:090127\S.Zaglio: added quotes around name because instance and - in some name
    v:090109\S.Zaglio: linked server extension only for table(not select)
    v:081020\S.Zaglio: count rows in select too
    v:081007\S.Zaglio: count rows in table
    t:begin declare @n int exec sp__count ''sysobjects'',@n out,@dbg=1 print @n end
    t:begin declare @n int exec sp__count ''select * from sysobjects where xtype=''''U'''''',@n out,@dbg=1 print @n end
    t:begin declare @n int exec sp__count ''sysobjects'',@n out,@svr=''loopback'',@dbg=1 print @n end
    t:begin declare @n int exec sp__count ''sysobjects'',@n out,@dbg=1,@where=''id<0'' print @n end
    t:begin declare @n int exec sp__count ''sys%'',@n out,@opt=''print'',@dbg=1 print @n end
*/
CREATE proc [dbo].[sp__count]
    @table nvarchar(4000)=null,
    @n bigint=null out,
    @where nvarchar(4000)=null,
    @opt sysname=null,
    @dbg bit=null
as
begin
-- set nocount on added to prevent extra result sets from
-- interfering with select statements.
set nocount on
-- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg''
declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id
select  @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0)
select  @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')
-- ========================================================= param formal chk ==
if @table is null goto help

-- ============================================================== declaration ==
declare
    @sql nvarchar(4000),
    @crlf nvarchar(2),
    @own sysname,@errl int,
    @svr sysname,@db sysname,
    @nn bigint,@params sysname,
    @print bit

declare @tbls table(obj sysname)

-- =========================================================== initialization ==

select
    @print=charindex(''|print|'',@opt),
    @n=0,
    @crlf=crlf,
    @svr=parsename(@table,4),
    @db=parsename(@table,3),
    @db=case when @svr is null then @db else isnull(@db,db_name()) end,
    @own=case when @db is null then null else isnull(parsename(@table,2),''dbo'') end,
    @svr=dbo.fn__sql_quotename(@svr),
    @db=dbo.fn__sql_quotename(@db),
    @params=N''@nn bigint out,@err int out''
from fn__sym()

-- ======================================================== second params chk ==
-- ===================================================================== body ==

-- simplify (n.b.: must converted into sp__sql_simplify or something similar. see also sp__count
select @table=replace(@table,@crlf,'' '')
select @table=rtrim(ltrim(@table))
select @table=replace(@table,''        '','' '')
select @table=replace(@table,''    '','' '')
select @table=replace(@table,''  '','' '')
select @table=replace(@table,''  '','' '')

if left(ltrim(@table),7)=''select ''
    insert @tbls select ''(''+@table+'') sq''
else
    insert @tbls(obj)
    select [name]
    from sysobjects
    where 1=1
    and xtype=''U''
    and [name] like @table

declare cs cursor local for
    select obj
    from @tbls
open cs
while 1=1
    begin
    fetch next from cs into @table
    if @@fetch_status!=0 break

    select @sql =''''
    select @sql =@sql+''select @nn=count(*) from ''+@table
                + coalesce('' where ''+@where,'''')+'' select @err=@@error''
    if not @db is null select @sql=''use ''+@db+'' ''+@sql

    if @dbg=1 exec sp__printsql @sql

    select @nn=0
    if @svr is null
        exec sp_executesql @sql,@params,@nn=@nn out,@err=@err out
    else
        begin
        select @sql =''exec ''+@svr+''.''+@db+''..sp_executesql N''''''
                    +dbo.fn__injectN(@sql)+'''''',N''''''+@params
                    +'''''',@nn=@nn out,@err=@err out''
        exec sp_executesql @sql,@params,@nn=@nn out,@err=@err out
        select @errl=@@error
        end
    if @err!=0 or @errl!=0 goto err_tbl
    if @print=1 exec sp__printf ''%s has %d rows'',@table,@nn
    select @n=@n+@nn

    end -- while of cursor
close cs
deallocate cs

goto ret

-- =================================================================== errors ==
err_tbl: exec @ret=sp__err ''near table "%s"'',@proc,@p1=@table goto ret
-- ===================================================================== help ==

help:
exec sp__usage @proc,''
Scope
    count the numbers of lines of a local or remote set of tables

Parameters
    @table  is the table name; can be svr.db.dbo.tbl;
            can use % and _ but in this case the
            target svr.db must be a tween of this.

Options
    print   print the results
''
-- ===================================================================== exit ==
ret:
return @ret
end -- sp__count'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__count:

-- ============================================================== sp__csv_export
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__csv_export',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=151106
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__csv_export') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__csv_export') with nowait
        goto skip_sp__csv_export
        end
    if @ver>151106
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__csv_export') with nowait
        goto skip_sp__csv_export
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__csv_export') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__csv_export'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__csv_export]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:export,csv
    v:151106\s.zaglio: added collate database_default
    v:121118.1800\s.zaglio: a bug when #obj
    v:121117\s.zaglio: export a tbl/view to csv file
    t:exec sp__csv_export ''cfg'',''c:\temp\tbl.csv'',@dbg=1
*/
CREATE proc sp__csv_export
    @obj sysname = null,
    @path nvarchar(1024) = null,
    @where sysname = null,
    @opt sysname = null,
    @dbg int=0
as
begin try
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
set nocount on
-- @@nestlevel is >1 if called by other sp

declare
    @proc sysname, @err int, @ret int  -- @ret: 0=OK -1=HELP, any=error id

-- ======================================================== params set/adjust ==

select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end,
    @where=replace(nullif(@where,''''),''"'',''''''''),
    @path=nullif(@path,'''')

-- ============================================================== declaration ==
declare
    -- generic common
    -- @i int,@n int,                   -- index, counter
    @sql nvarchar(max),                 -- dynamic sql
    @flds nvarchar(4000),
    -- options
    @noq bit,                           -- no quotes
    @noh bit,                           -- no header
    @crlf nvarchar(2),
    @cn nvarchar(128),
    @temp nvarchar(4000),               -- temp path
    @line nvarchar(4000),
    @out bit,
    @obj_id int,
    @psep nchar(1),                     -- path separator
    @dt datetime,
    @end_declare bit

declare @cols table(
    pos int,col sysname,
    last bit,
    cc nvarchar(4000),                  -- convert cmd
    hdr sysname null,
    ct sysname null,                    -- column type
    cs nvarchar(4)                      -- convert style
    )

-- =========================================================== initialization ==
exec sp__get_temp_dir @temp out

select
    @dt=getdate(),
    @noq=charindex(''|noq|'',@opt),
    @noh=charindex(''|noh|'',@opt),
    @crlf=crlf,
    @path=replace(@path,''%temp%'',@temp),
    -- sp__format
    @path=replace(@path,''%dt%'',dbo.fn__format(@dt,''yyyymmdd_hhmmss'',default)),
    @path=replace(@path,''%yyyymmdd%'',convert(sysname,@dt,112)),
    @path=replace(@path,''%yymmdd%'',convert(sysname,@dt,12)),
    @path=replace(@path,''%hhmmss%'',dbo.fn__format(@dt,''hhmmss'',default)),
    @path=replace(@path,''%hhmm%'',dbo.fn__format(@dt,''hhmm'',default)),
    @out=isnull(object_id(''tempdb..#out''),0),
    @obj_id=isnull(object_id(case when left(@obj,1)=''#''
                             then ''tempdb..''+@obj
                             else @obj
                             end),0),
    @end_declare=1
-- select *
from fn__sym()

-- ======================================================== second params chk ==
if @obj is null and @path is null goto help

if @out=0
    create table #out(lno int identity primary key,line nvarchar(4000))

-- ===================================================================== body ==

if @obj_id=0 and @out=0     raiserror(''object "%s" not found'',16,1,@obj)
if @path is null and @out=0 raiserror(''path not specified'',16,1)
if right(@path,1)=@psep     raiserror(''path without file name'',16,1)
if @path is null and @obj_id=0 and @out=1
                            raiserror(''path or obj must specified'',16,1)

if @obj_id=0 goto file_write

exec sp__flds_list @flds out,@obj

if @flds is null raiserror(''no fields found for specified table'',16,1)

insert @cols(pos,col)
select pos,token
from dbo.fn__str_table(@flds,''|'')

update c set
    ct=token,
    cs=case when token like ''%date%'' collate database_default then '',126'' else '',0'' end
from @cols c
join dbo.fn__str_table(dbo.fn__flds_type_of(@obj,'','',null),'','') t
on c.pos=t.pos

select @cn=''convert(nvarchar(4000),isnull(''
update @cols set last=1 where pos=(select max(pos) from @cols)

update @cols
set cc =case @noq when 1 then '''' else ''''''"''''+'' end
       +case @noq when 1
        then @cn+col+'','''''''')''+cs+'')''
        else ''replace(''+@cn+col+'','''''''')''+cs+''),''''"'''',''''""'''')''
        end
       +case @noq when 1 then '''' else ''+''''"'''''' end,
    hdr=case @noq when 1 then '''' else ''"'' end
       +case @noq when 1
        then parsename(col,1)
        else replace(parsename(col,1),''"'',''""'')
        end
       +case @noq when 1 then '''' else ''"'' end

if @dbg=1 select * from @cols

if @noh=0
    begin
    select @line=null
    select @line=isnull(@line+'','','''')+hdr from @cols
    insert #out(line) select @line
    end -- header

-- compound the select
select @sql =isnull(@sql+''+'''',''''+''+@crlf,'''')+cc
from @cols
order by pos

if @sql is null raiserror(''bad inside code generation'',16,1)

select @sql =''insert #out(line)''+@crlf
            +''select ''+@crlf
            +@sql
            +@crlf+''as line ''
            +@crlf+''from [''+@obj+''] ''+@crlf
            +case when not @where is null
             then ''where ''+@where
             else ''''
             end

if @dbg>0 exec sp__printsql @sql

exec(@sql)
/*
drop table #out
sp__csv_export ''cfg'' -- error test
create table #out(lno int identity primary key,line nvarchar(4000))
select * into #cfg from cfg -- select * from #cfg
truncate table #out exec sp__csv_export ''#cfg'',@opt=''noh'' select * from #out
sp__csv_export @path=''%temp%\text.txt''

sp__csv_export ''cfg'',@path=''%temp%\text.txt'',@where=''[key] like "%"'',@dbg=1
xp_cmdshell ''type %temp%\text.txt''
xp_cmdshell ''del %temp%\text.txt''
*/

file_write:
if @dbg>0 select @path,* from #out
if not @path is null
    exec @ret=sp__file_write_stream @path,@fmt=''ascii'',@opt=''out''

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.
if @out=0 drop table #out
goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    export an object(table or view) to a text file, formatted as CSV
    (Comma Separated Values).

Notes
    when a comma is present in the value, automatically will be quoted "";
    when a " is present in the value, automatically will be doubled;
    default export format is ASCII

Parameters
    @obj    name of object to export; can be a #tbl
    @path   path of destination file; supporto macros:
            %temp%      value of cmd line environment
            %DT%        same of YYYYMMDD_HHMMSS
            %YYYYMMDD%  year month day
            %YYMMDD%    year month day
            %HHMMSS%    hour minutes seconds
            %HHMM%      hour minutes
    #out    if @path is null, insert lines into #out
            if @path is valued and @obj is null, save #out to @path
            create table #out(lno int identity primary key,line nvarchar(4000))
    @where  optional condition for @obj
    @opt    options
            noq     suppress quotes " around the value of each field
                    (if value will contain a , will cause a bad input)
            noh     suppress export of 1st line containing column names

Examples
    exec %proc% "tbl","%temp%\tbl.csv"
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret

end try
-- =================================================================== errors ==
begin catch
exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__csv_export'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__csv_export:

-- ============================================================== sp__csv_import
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__csv_import',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121205.1000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__csv_import') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__csv_import') with nowait
        goto skip_sp__csv_import
        end
    if @ver>121205.1000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__csv_import') with nowait
        goto skip_sp__csv_import
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__csv_import') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__csv_import'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__csv_import]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:import,csv
    o:130902\s.zaglio: sp__csvio
    o:130902\s.zaglio: sp__csvio_on
    v:121205.1000\s.zaglio: done test into table and #table
    r:121130\s.zaglio: improved import of bigger files
    r:121118\s.zaglio: load csv into a table
*/
CREATE proc sp__csv_import
    @path nvarchar(1024) = null,
    @tbl sysname = null,
    @opt sysname = null,
    @dbg int=0
as
begin try
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
set nocount on
-- @@nestlevel is >1 if called by other sp

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @e_msg nvarchar(2000)               -- used for big raiserror msgs

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end,
    @path=nullif(@path,'''')

-- ============================================================== declaration ==
declare
    @run bit,
    @tmp nvarchar(4000), @size int,
    @fmt sysname,
    @ls int,
    @l int,@i int,@row int,@col smallint,@j int,
    @cmd sysname,@hr int,@adodbstream int,
    @sep nvarchar(1),@q nvarchar(1),
    @qlf nvarchar(2),@qcr nvarchar(2),@qsep nvarchar(2),@qsp nvarchar(2),
    @txt nvarchar(max),@cc nvarchar(2),@qq nvarchar(2),
    @dq bit,                            -- double quote marker
    @ncols int,                         -- counter of max n cols
    @crlf nvarchar(2),
    @flds nvarchar(4000),
    @nflds int,
    @noh bit,
    @d datetime,
    @tbl_id int,                        -- test existance
    @end_declare bit

create table #sp__csv_import_fld(
    row int,col smallint,
    pos int,ln int,dq bit,
    primary key(row,col)
    )

create table #sp__csv_import_text(txt nvarchar(max))

-- =========================================================== initialization ==
select
    @noh=charindex(''|noh|'',@opt),
    @sep='','',@q=''"'',@qq=@q+@q,@qlf=@q+lf,@qcr=@q+cr,@qsep=@q+@sep,@qsp=@q+'' '',
    @ls=-1,
    @dq=0,
    @fmt=''utf-8'',
    @crlf=crlf,
    @tbl_id=case
            when left(@tbl,1)=''#''
            then object_id(''tempdb..''+quotename(@tbl))
            else object_id(quotename(@tbl))
            end,
    @flds=dbo.fn__flds_of(@tbl,'','',null),
    @ncols=0,@nflds=0,
    @end_declare=1
from fn__sym()
select @nflds=dbo.fn__str_count(@flds,'','')

-- ======================================================== second params chk ==
if @path is null goto help

-- =============================================================== #tbls init ==

-- ===================================================================== body ==

/*
    @fmt    is the format of source file; by default is "utf-8"
            Other format are gived from constants acecpted by
            adodb.stream "charset" property.
    @ls     line separator (default -1 for CRLF else 10 for LF or 13 for CR)
            Unfortunatelly, MSSQL generates log that are incompatibile with
            this (or after too many tests I have not found one good)
            In that case the old xp_cmdshell "type ..." work well.
*/

-- drop table #buffer

if @path like ''%[%]temp[%]%''
    begin
    exec sp__get_temp_dir @tmp out
    select @path=replace(@path,''%temp%'',@tmp)
    if @dbg=1 exec sp__printf ''path:%s'',@path
    end

if @path like ''%..%'' raiserror(''worked protection against hackers :-)'',16,1)

select @size=4000

if @dbg=1 exec sp__elapsed @d out,''init stream''

select @cmd=''ADODB.Stream''
exec @hr = sp_oacreate @cmd, @adodbstream out
if @hr!=0 goto dispose
select @cmd=''Type''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,2 -- text
if @hr!=0 goto dispose
select @cmd=''charset''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,@fmt
if @hr!=0 goto dispose
select @cmd=''LineSeparator''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,@ls
if @hr!=0 goto dispose
select @cmd=''Open''
exec @hr = sp_oamethod  @adodbstream , @cmd, null
if @hr!=0 goto dispose
select @cmd=''LoadFromFile''
exec @hr = sp_oamethod  @adodbstream , @cmd, null, @path
if @hr!=0 goto dispose
select @cmd=''ReadText''

insert #sp__csv_import_text
exec @hr = sp_oamethod  @adodbstream , @cmd, null

if @hr!=0 goto dispose
exec @hr = sp_oadestroy @adodbstream
select @adodbstream=null

if @dbg=1 exec sp__elapsed @d out,''after load''

-- parse file
select top 1 @txt=txt,@l=len(@txt) from #sp__csv_import_text
select
    @i=charindex(@q,@txt)+1,    -- search first open quote
    @j=@i,
    @row=1,
    @col=1

if @i=1 raiserror(''no open quote found'',16,1)

if @dbg=1 exec sp__printf ''qsep=%s  l=%d  nflds=%s'',@qsep,@l,@nflds

while (@i<@l and @i>0)
    begin
    /*  1. load file into nvarchar(max)
        2. if format ",
        3. scan for 1st "
        4. scan for next " and take 2 chars
        5. if "" skip 2 and goto 4
        6. if ", store, next field, skip 2 and goto 4
        7. if "#13 or "#10 new line                                         */

    select @i=@i+1                  -- skip open quote
    select @i=charindex(@q,@txt,@i) -- search next quote close
    if @i=0 break;                  -- file must end with last quote
    select @cc=substring(@txt,@i,2)
    -- exec sp__printf ''r=%d c=%d j=%d i=%d, cc=%s'',@row,@col,@j,@i,@cc
    if @cc=@qq                      -- skip double quote
        begin
        select @i=@i+1,@dq=1
        continue                    -- skip inner quote
        end
    if @cc=@qsep or @cc=@qcr or @cc=@qlf or @cc=@qsp    -- new row
        begin
        insert #sp__csv_import_fld(row,col,pos,ln,dq)
        select @row,@col,@j,(@i-@j),@dq
        if @cc!=@qcr and @cc!=@qlf
            select @col=@col+1,@dq=0
        else
            begin
            -- exec sp__printf ''ncols=%d, col=%d'',@ncols,@col
            if @ncols<@col select @ncols=@col
            if @ncols!=@col
                raiserror(
                    ''different number of cols in row %d'',
                    16,1,@row
                    )
            if @row=1
                begin
                if @ncols>999
                    raiserror(''max 999 rows admitted'',16,1)
                if @nflds=0 select @nflds=@ncols
                if @nflds!=@ncols
                    begin
                    select @e_msg=''number of source cols(%d) ''
                                 +''differ from destination(%d)''
                    raiserror(@e_msg,16,1,@ncols,@nflds)
                    end
                end
            select @row=@row+1,@col=1,@dq=0
            end
        select @j=0
        end

    -- search next open quote
    select @i=@i+1                  -- skip close quote
    select @i=charindex(@q,@txt,@i) -- search next open quote
    select @j=@i+1                  -- mark start of field
    end -- scan loop

if @j>1 raiserror(''file do not correclty end with a quote'',16,1)

if @dbg=1 exec sp__elapsed @d out,''after parsing''

if @dbg>0
    select
        *,
        case dq when 0
        then substring(@txt,pos,ln)
        else replace(substring(@txt,pos,ln),@qq,@q)
        end as fld
    from #sp__csv_import_fld

-- sp__csv_import ''c:\shared_folders\backup_db\csv_test.txt'',@opt=''noh'',@dbg=1
-- drop table csv_test
-- sp__csv_import ''c:\shared_folders\backup_db\csv_test.txt'',@tbl=''csv_test''
-- select * from csv_test -- select * from #t
-- truncate table csv_test  -- drop table #t
-- select top 0 * into #t from csv_test --alter table #t drop column [last col]
-- truncate table #t
-- sp__csv_import ''c:\shared_folders\backup_db\csv_test.txt'',@tbl=''#t'',@dbg=1
if @flds is null
    select @flds=isnull(@flds+'','','''')
                +case @noh
                 when 0
                 then replace(substring(@txt,pos,ln),@qq,@q)
                 else ''c''+dbo.fn__format(col,''0'',len(@ncols))
                 end

    from #sp__csv_import_fld
    where row=1


-- Pivot table
select @txt=''
%insert%
select %alias%   -- [1] as a,[2] as b,...
%into%
from (
    select
        row,col,
        case dq when 0
        then substring(txt,pos,ln)
        else replace(substring(txt,pos,ln),''''''+@qq+'''''',''''''+@q+'''''')
        end as fld
    from #sp__csv_import_fld,#sp__csv_import_text
    ''+case @noh when 1 then '''' else ''where row>1'' end +''
    ) as src
pivot
(
    max(fld) for col in (%col%) -- [1],[2],...
) as result
''

select @txt=replace(@txt,
                    ''%alias%'',
                    dbo.fn__str_exp(''[%idx%] as [%%]'',@flds,'','')
                    )
select @txt=replace(@txt,''%col%'',dbo.fn__str_exp(''[%idx%]'',@flds,'',''))

if not @tbl is null
    begin
    if @tbl_id is null
        select @txt=replace(
                        replace(@txt,''%insert%'',''''),
                        ''%into%'',
                        ''into ''+@tbl
                        )
    else
        select @txt=replace(
                        replace(@txt,''%insert%'',''insert into ''+@tbl),
                        ''%into%'',
                        ''''
                        )
    end
else
    select @txt=replace(replace(@txt,''%insert%'',''''),''%into%'','''')

if @dbg=1 exec sp__printsql @txt
exec(@txt)

if @dbg=1 exec sp__elapsed @d out,''after pivot and out''

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.
if @hr!=0
    begin
    declare @source nvarchar(255)
    declare @description nvarchar(255)

    exec @hr = sp_oageterrorinfo @adodbstream, @source out, @description out
    raiserror(''ole error (%s;%s;%s)'',16,1,@cmd,@source,@description)
    end

if not @adodbstream is null
    begin
    exec @hr = sp_oadestroy @adodbstream
    select @adodbstream=null
    end

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    load a csv file and store it into a table

Notes
    - this replace old SP__CSV_IN
    - actually import only comma separated values closed into double quotes

Parameters
    @path   is the path of the file; if end with \ will loaded all .csv/.txt
    @tbl    is the name of destination table; if not exists will be created
            if not specified will used the name of file without extension
            can be a #temp table
    @opt    options
            noh     no header in the first line

See
    sp__csv_export

Examples
    sp__csv_import "%temp%\customers.txt
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end try

-- =================================================================== errors ==
begin catch
if not @adodbstream is null
    begin
    exec @hr = sp_oadestroy @adodbstream
    select @adodbstream=null
    end

exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__csv_import'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__csv_import:

-- =================================================================== sp__csvio
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__csvio',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100509
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__csvio') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__csvio') with nowait
        goto skip_sp__csvio
        end
    if @ver>100509
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__csvio') with nowait
        goto skip_sp__csvio
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__csvio') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__csvio'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__csvio]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100509\s.zaglio: define structure for txt i/o
    todo: convert csvio into a tree structure
    t:
        sp__dir ''f:\sapshare''
        truncate table csvio
        sp__csvio
*/
CREATE proc [dbo].[sp__csvio]
    @tbl nvarchar(64)=null,
    @fld nvarchar(32)=null,
    @offset int=null,
    @len int=null,
    @info nvarchar(1024)=null,
    @rid sysname=0,
    @out sysname=null,
    @dbg bit=0
as
begin
set nocount on
declare @proc sysname,@ret int
select @proc=''sp__csvio'',@ret=0

if @tbl is null and @fld is null goto help

-- declaration
declare
    @tid tinyint,@rows int,@sql nvarchar(4000),
    @upd bigint,@ins bigint,@del bigint

-- init and addjust
if object_id(''csvio'') is null
    begin
    select @sql=''
    create table csvio(
        tid tinyint,
        id int identity primary key nonclustered,
        rid int not null,                   -- doc parent if this is a sub-segment
        des nvarchar(64) null,              -- tbl
        cod nvarchar(32) null,              -- fld
        flags int null,                     -- (not used)
        idx int not null,                   -- offset
        n   int not null,                   -- len
        at  datetime default (getdate()),   -- update, version
        dat nvarchar(1024) null             -- description
        )
    create clustered index csvio_tid on csvio (tid)''
    if @dbg=1 exec sp__printf ''%s'',@sql else exec(@sql)
    end -- create

select
    @tid=1,
    @out=dbo.fn__sql_unquotename(@out),
    @info=replace(@info,'''''''','''''''''''')

create table #vars (id nvarchar(16),value sql_variant)
insert #vars values(''"'',        '''''''')
insert #vars values(''%tid%'',    @tid)
insert #vars values(''%rid%'',    @rid)
insert #vars values(''%tbl%'',    @tbl)
insert #vars values(''%fld%'',    @fld)
insert #vars values(''%offset%'', @offset)
insert #vars values(''%len%'',    @len)
insert #vars values(''%info%'',   @info)
insert #vars values(''%out%'',    @out)

-- create out table
if not @tbl is null and @fld is null and @offset is null and @len is null and @info is null
and not @out is null
    begin
    select @sql=null
    select @sql=coalesce(@sql+'','','''')+quotename(cod)+'' nvarchar(''+convert(sysname,[n])+'')''
    from csvio
    where tid=@tid and rid=@rid
    and [des]=@tbl
    order by idx
    select @sql=''
    if not object_id("%out%") is null drop table [%out%]
    create table [''+@out+''](''+@sql+'')''
    end


-- list tbl fields
if not @tbl is null and @fld is null and @offset is null and @len is null and @info is null
and @out is null
    select @sql=''
        select des as tbl, cod as fld, idx as offset,n as [len], at as [updt],dat as info
        from csvio
        where tid=%tid% and rid=%rid%
        and des like "%tbl%%"
        order by des,idx
    ''


-- deletes


-- delete table
if not @tbl is null and @fld=''*'' and @offset is null
and @len is null and @info is null
    select @sql=''
    update csvio set tid=0 where tid=%tid% and rid=%rid% and des like "%tbl%%"
    select @del=@@rowcount
    ''

-- delete fields
if not @tbl is null and not @fld is null and @offset is null
and @len is null and @info is null
    select @sql=''
    update csvio set tid=0 where tid=%tid% and rid=%rid% and des="%tbl%" and cod like "%fld%%"
    select @del=@@rowcount
    ''

-- add/upd tbl/fld
if not @tbl is null and not @fld is null and not @offset is null
and not @len is null
    select @sql=''
        update csvio set idx=%offset%, n=%len%, dat="%info%"
        where tid=%tid% and rid=%rid% and des="%tbl%" and cod="%fld%"
        select @upd=@@rowcount
        if @upd=0
            begin
            insert csvio(tid,rid,des,cod,idx,n,dat)
            select %tid%,%rid%,"%tbl%","%fld%",%offset%,%len%,"%info%"
            select @ins=@@rowcount
            end
        ''


if not @sql is null
    begin
    exec sp__str_replace @sql out,@tbl=1
    if @dbg=1 exec sp__printf ''%s'',@sql
    else
        begin
        select @ins=0,@upd=0,@del=0
        exec sp_executesql @sql,
            N''@ins bigint out,@upd bigint out,@del bigint out'',
            @ins=@ins out,@upd=@upd out,@del=@del out
        if @out is null exec sp__printf ''-- %d rows inserted, %d updated,%d freed'',@ins,@upd,@del
        else exec sp__printf ''-- table dropped and recreated''
        end
    end


goto ret

help:
exec sp__usage @proc,''
Examples
    sp__csvio                                    -->this help
    sp__csvio @tbl                               -->list tbl fields
    sp__csvio @tbl,@fld,@offset,@len,@info       -- add or update
    sp__csvio @tbl,@fld                          -- delete
    sp__csvio @tbl,''''*''''                         -- delete table

    sp__csvio_in @path,@table,@definition

''

ret:
return @ret
end -- sp__csvio'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__csvio:

-- ================================================================ sp__csvio_in
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__csvio_in',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100509
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__csvio_in') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__csvio_in') with nowait
        goto skip_sp__csvio_in
        end
    if @ver>100509
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__csvio_in') with nowait
        goto skip_sp__csvio_in
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__csvio_in') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__csvio_in'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__csvio_in]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100509\s.zaglio: inport a txt file into a table with csvio
    t:sp__csvio_in ''c:\autoexec.bat'',''test''
*/
CREATE proc [dbo].[sp__csvio_in]
    @path   nvarchar(512)=null,
    @out    sysname=null,
    @def    sysname=null,
    @dbg    bit=0
as
begin
set nocount on
declare @proc sysname,@ret int
select @proc=''sp__csvio_in'',@ret=0

if @path is null and @out is null goto help

if @def is null select @def=@out

if not exists(select null from csvio where tid=1 and des=@def) goto err_def

-- declaration
declare
    @tid tinyint,
    @sql nvarchar(4000)

create table #src(lno int identity,line nvarchar(4000))

-- init and addjust

select
    @tid=1

create table #vars (id nvarchar(16),value sql_variant)
insert #vars values(''"'',        '''''''')

-- inport text (read utf8/unix/win txt files)
exec sp__file_read_stream @path,@out=''#src'',@dbg=@dbg

-- filter columns
select @sql=null
select @sql =coalesce(@sql+'','','''')+''substring(line,''+convert(sysname,idx)+'',''+convert(sysname,n)+'') ''
            +quotename(cod)
from csvio
where tid=@tid
and des=@def

if @out is null
    select @sql=''select ''+@sql+'' from #src order by lno''
else
    select @sql=''insert ''+@out+'' select ''+@sql+'' from #src order by lno''

if @dbg=1 exec sp__printf ''%s'',@sql
else exec(@sql)

drop table #src

goto ret

err_def:    exec @ret=sp__err ''definition "%s" not found'',@proc,@p1=@def    goto ret

help:
exec sp__usage @proc,''
''
select @ret=-1

ret:
return @ret
end -- sp__csvio'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__csvio_in:

-- ================================================================== sp__db_md5
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__db_md5',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=090908
        begin
        if @aut!='S.Zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__db_md5') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__db_md5') with nowait
        goto skip_sp__db_md5
        end
    if @ver>090908
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__db_md5') with nowait
        goto skip_sp__db_md5
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__db_md5') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__db_md5'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__db_md5]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:090908/S.Zaglio: added some usefull query in comments
    v:081001/S.Zaglio: added calc of stored, function,view,triggers,
    v:080808/S.Zaglio: calculate hash md5 or entire list of table+colums def
    t:
    begin -- each call require 1 minute
    declare @m binary(16), @sql nvarchar(500)
    declare @dbg bit set @dbg=@dbg
    drop proc test_sp__db_md5
    drop table test_sp__db_md5
    print '''' print ''original md5 of all db and retest''
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    -- test differencies
    print '''' print ''test add column to table''
    ALTER   table test_sp__db_md5 (a int)
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    ALTER  table test_sp__db_md5 add b bigint
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    drop table test_sp__db_md5
    print '''' print ''test after drop table''
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)

    -- test proc
    print '''' print ''test md5 all db after ALTER  proc''
    set @sql=''ALTER  proc test_sp__db_md5 as print 1'' exec(@sql)
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    print '''' print ''test md5 of single proc''
    set @sql=''alter proc test_sp__db_md5 as print 1'' exec(@sql)
    exec sp__db_md5 @m out,''test_sp__db_md5'',@dbg=@dbg print dbo.fn_hex(@m)
    print '''' print ''test alter proc to same but probably create change to alter''
    set @sql=''alter proc test_sp__db_md5 as print 1'' exec(@sql)
    exec sp__db_md5 @m out,''test_sp__db_md5'',@dbg=@dbg print dbo.fn_hex(@m)
    print '''' print ''test alter proc to same again''
    set @sql=''alter proc test_sp__db_md5 as print 1'' exec(@sql)
    exec sp__db_md5 @m out,''test_sp__db_md5'',@dbg=@dbg print dbo.fn_hex(@m)
    print '''' print ''test alter 1 nchar of same proc''
    set @sql=''alter proc test_sp__db_md5 as print 2'' exec(@sql)
    exec sp__db_md5 @m out,''test_sp__db_md5'',@dbg=@dbg print dbo.fn_hex(@m)
    drop proc test_sp__db_md5
    print '''' print ''test not existance after drop proc''
    exec sp__db_md5 @m out,''test_sp__db_md5'',@dbg=@dbg print dbo.fn_hex(@m)
    print '''' print ''original md5 of all db''
    exec sp__db_md5 @m out,@dbg=@dbg print dbo.fn_hex(@m)
    end
*/
CREATE  proc [dbo].[sp__db_md5]
    @db_md5 binary(16)=null out,
    @objects nvarchar(4000)=null,
    @dbg bit=0
as
begin
set nocount on
create table #objs ([id] int, [name] sysname, [xtype] nchar(2), md5 binary(16))
declare @n int
declare @i int set @i=1
declare @id int, @last_id int, @colid smallint
declare @obj sysname
declare @xtype nchar(2)
declare @output bit
if @db_md5 is null set @output=1
if @objects is null insert into #objs([id],[name],[xtype])
    select [id],[name],[xtype] from sysobjects where xtype in (''U'',''V'',''P'',''FN'',''TR'',''D'',''IF'',''TF'',''F'',''UQ'',''PK'',''C'',''RF'')
else begin
    set @n=dbo.fn__str_count(@objects,''|'')
    while (@i<=@n) begin
        set @obj=dbo.fn__str_at(@objects,''|'',@i)
        set @id=object_id(@obj)
        if @id is null and @dbg=@dbg print ''object ''+@obj+'' don''''t exists''
        else begin
            select @xtype=xtype from sysobjects where id=@id
            insert into #objs(id,name,xtype) values(@id,@obj,@xtype)
        end
        set @i=@i+1
    end -- while
end
if @dbg=@dbg begin
    select @n=count(*) from #objs
    print ''objects selected ''+convert(nvarchar(32),@n)
end
-- todo: indexes not pk,uq are excluded. Must be integreted
-- check tables
declare cst cursor local forward_only static read_only for
select    top 100 percent o.id, o.name as [name], o.name + ''|'' + c.name + ''|'' + t.name + ''|'' + convert(nvarchar(32), isnull(c.length, 0)) + ''|'' + convert(nvarchar(32),
          isnull(c.xprec, 0)) + ''|'' + convert(nvarchar(32), isnull(c.scale, 0)) as row
from      syscolumns c inner join
          #objs o on c.id = o.id inner join
          systypes t on c.xtype = t.xtype
where     o.xtype=''U''
order by o.id, c.colid
declare @a bigint,@b bigint, @c bigint, @d bigint
set @db_md5=null
set @last_id=null
declare @row nvarchar(4000)
open cst
while (1=1) begin
    fetch next from cst into @id,@obj,@row
    if @@error!=0 or @@fetch_status!=0 break
    if coalesce(@last_id,0)<>@id and @dbg=@dbg print ''calculating md5 of table ''+@obj
    if @last_id is null set @last_id=@id
    if @last_id<>@id set @last_id=@id
    exec sp__md5 @row,@db_md5 out,@a out,@b out,@c out,@d out
end -- while
close cst
deallocate cst
if @dbg=@dbg print ''calculate for other ojects''
-- check procs, funcs, views, etc.
declare csp cursor local forward_only static read_only for
select o.id,sc.colid,o.name
from syscomments sc
inner join #objs o on sc.id=o.id
where o.xtype != ''U''
order by sc.id,sc.colid
option (robust plan)
set @last_id=null
declare @row1 nvarchar(4000)
open csp
while (1=1) begin
-- Impossibile creare una riga di tabella di lavoro con dimensioni maggiori
-- della larghezza massima consentita. Rieseguire la query con l''hint ROBUST PLAN.
    fetch next from csp into @id,@colid,@obj
    if @@error!=0 or @@fetch_status!=0 break
    select @row=coalesce(substring([text],1,4000),''''),@row1=coalesce(substring([text],4001,4000),'''')
    from syscomments where id=@id and colid=@colid
    if coalesce(@last_id,0)<>@id and @dbg=@dbg print ''calculating md5 of object ''+@obj
    if @last_id is null set @last_id=@id
    if @last_id<>@id set @last_id=@id
    if len(@row1)=0
        exec sp__md5 @row,@db_md5 out,@a out,@b out,@c out,@d out
    else begin
        exec sp__md5 @row ,@db_md5 out,@a out,@b out,@c out,@d out
        exec sp__md5 @row1,@db_md5 out,@a out,@b out,@c out,@d out
    end
end -- while
close csp
deallocate csp
drop table #objs
if @output=1 select @db_md5
end -- proc'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__db_md5:

-- ================================================================== sp__delete
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__delete',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=081219
        begin
        if @aut!='S.Zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__delete') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__delete') with nowait
        goto skip_sp__delete
        end
    if @ver>081219
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__delete') with nowait
        goto skip_sp__delete
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__delete') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__delete'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__delete]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:081219\S.Zaglio: delete a random row of a table
    t:sp__delete ''ot04_stock'',@random=1,@dbg=1  -- delete and reinsert a random line
    t:sp__delete ''as_f0005'',@random=1,@dbg=1  -- delete and reinsert a random line
    t:sp__delete ''as_f0101j2'',@where=''abat1="w"'',@random=1,@dbg=1  -- delete and reinsert a random line
*/
CREATE proc sp__delete
    @table sysname=null,
    @where nvarchar(4000)=null,
    @rows bigint=null out,
    @random bit=0,
    @dbg bit=0
as
begin
set nocount on
declare @crlf nvarchar(2) set @crlf=char(13)+char(10)
if @table is null begin
    exec sp__usage ''sp__delete''
    goto ret
end

declare    @from nvarchar(4000)
declare    @flds nvarchar(4000)
declare    @excludes nvarchar(4000)
declare    @col_sep nvarchar(8) set @col_sep=''|''
declare    @row_sep nvarchar(8)

if @row_sep is null set @row_sep=@crlf

declare @i int, @col int, @cols int
declare @sql nvarchar(4000)
declare @values nvarchar(4000)
declare @row nvarchar(4000)
declare @value sysname
declare @consts bit set @consts=0
declare @s sysname
if @where='''' set @where=null else set @where=replace(@where,''"'','''''''')
if @random=1 begin
    set @flds=dbo.fn__flds_of(@table,'','',@excludes)
    if @where is null begin
        set @sql=''SELECT top 1 ''+@flds+'' FROM ''+@table+'' ORDER BY newid() desc'' -- get a random line
    end
    else begin
        -- set @where=dbo.fn__inject(@where)
        if left(ltrim(@where),6)!=''where '' set @where='' where ''+@where
        set @sql=''SELECT top 1 ''+@flds+'' FROM ''+@table+'' ''+@where+'' ORDER BY newid() desc'' -- get a random line
    end
    set @values=''''
    exec sp__select @sql,@body=@values out,@null=''(/null/)'',@dtstyle=126,@dbg=@dbg
    set @values=dbo.fn__inject(@values)
    set @flds=replace(@flds,'','','' and '')
    set @flds=dbo.fn__str_exp(dbo.fn__str_exp(''%%=''''@@'''''',@flds,'' and ''),@values,''|'')
    set @where ='' WHERE ''+@flds
    set @where=replace(@where,''=''''(/null/)'''''','' is null '')
    set @sql=''DELETE FROM ''+@table+@where
    if @dbg=1 exec sp__printf @sql
    exec(@sql) set @rows=@@rowcount
    if @rows!=1 begin print ''no deleted row'' goto err end
    goto ret
end
else print ''no other extensions done''
goto ret
err:
ret:
end -- proc'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__delete:

-- =============================================================== sp__dependent
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__dependent',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130521.1000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__dependent') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__dependent') with nowait
        goto skip_sp__dependent
        end
    if @ver>130521.1000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__dependent') with nowait
        goto skip_sp__dependent
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__dependent') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__dependent'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__dependent]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:list,depend,object,dependencies,tree
    v:130521.1000\s.zaglio: print the tree of dependencies of an object
    t:sp__depends ''sp__script''
*/
CREATE proc sp__dependent
    @obj sysname = null,
    @level int = null,
    @opt sysname = null,
    @dbg int=0
as
begin try
/*
    originally from
      http://stackoverflow.com/questions/379649/
           t-sql-puzzler-crawling-object-dependencies
*/
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
-- @@nestlevel is >1 if called by other sp

set nocount on

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @err_msg nvarchar(2000)             -- used before raise

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end
    -- @param=nullif(@param,''''),

-- ============================================================== declaration ==
declare
    @crlf nvarchar(2),
    @txt nvarchar(max),
    @sub sysname

-- =========================================================== initialization ==
select
    @level=isnull(@level+1,0),
    @crlf=crlf
from fn__sym()

-- ======================================================== second params chk ==
if @obj is null goto help

-- =============================================================== #tbls init ==
if object_id(''tempdb..#deptree'') is null
    create table #deptree(id int identity,lv int,obj sysname)

-- ===================================================================== body ==

-- print replicate('' '',@level) + @obj
insert #deptree values(@level,@obj)

declare cs cursor local for
    select
        distinct c.name
    from dbo.sysdepends a
        inner join dbo.sysobjects b on a.id = b.id
        inner join dbo.sysobjects c on a.depid = c.id
    where b.name = @obj
open cs
while 1=1
    begin
    fetch next from cs into @sub
    if @@fetch_status != 0 break
    -- if already marked, skip to avoid max recurse error
    if not exists(select top 1 null from #deptree where obj=@sub)
        exec sp__dependent @sub, @level
    end
close cs
deallocate cs

-- =============================================================== print tree ==

if @level=0
    begin
    select @txt=isnull(@txt+@crlf,'''')+replicate('' '',lv)+obj
    from #deptree
    exec sp__printsql @txt
    end


-- ================================================================== dispose ==
dispose:
if @level=0 drop table #deptree

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    print the dependency tree of the object, without repeat already printed
    objects

Parameters
    [param]     [desc]
    @obj        the object where find dependencies
    @level      used internally
    @opt        options
    @dbg        not used

Examples
    sp__depends "sp__script"
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end try

-- =================================================================== errors ==
begin catch
-- if @@trancount > 0 rollback -- for nested trans see style "procwnt"

exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__dependent'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__dependent:

-- ============================================================== sp__deprecated
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__deprecated',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=140103
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__deprecated') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__deprecated') with nowait
        goto skip_sp__deprecated
        end
    if @ver>140103
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__deprecated') with nowait
        goto skip_sp__deprecated
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__deprecated') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__deprecated'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__deprecated]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:deprecate,list
    d:140127\s.zaglio:fn__street
    d:140127\s.zaglio:sp_info
    d:140103\s.zaglio:sp_find
    d:130806\s.zaglio:sp__parse
    d:130806\s.zaglio:sp__parse_test
    v:140103\s.zaglio:list only objects to deprecate
*/
CREATE proc sp__deprecated
as
begin
set nocount on
declare @proc sysname
select  @proc=object_name(@@procid)
-- ===================================================================== help ==
exec sp__usage @proc,''
Scope
    give only a list of generic (old) objects deprecated or obsolete

Notes
    Eventually you can describe the reason here.

Examples
    sp__parse,sp__parse_test:   never used, will be replaced by a generic parser
                                extracted from golden parser
''

-- ===================================================================== exit ==
ret:
return -1
end -- sp__deprecated'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__deprecated:

-- ===================================================================== sp__dir
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__dir',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131117.1000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__dir') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__dir') with nowait
        goto skip_sp__dir
        end
    if @ver>131117.1000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__dir') with nowait
        goto skip_sp__dir
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__dir') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__dir'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__dir]

begin try
exec dbo.sp_executesql @statement = N'/*  Leave this unchanged doe MS compatibility
    l:see LICENSE file
    g:utility
    v:131117.1000\s.zaglio:more detailed dbg info and enlarged @files.key size
    v:131021\s.zaglio:some correction near use of @kp
    v:131018\s.zaglio:corrected a bug if under mssql2k5
    v:131016.1000,131015,131014\s.zaglio: adding list of sub directory and unicode support
    v:130906,130904\s.zaglio: better help;added more debug info and (net) errors check
    v:130424,130227\s.zaglio: avoid #files when used with shortkey(* option);a small bug near full search
    v:130115,121116\s.zaglio: added grp: option;a bug near extra drop of #src
    v:121010\s.zaglio: in * opt, search _word% and word% added @isql
    v:120926,120919\s.zaglio: print instead of select and +select option;added # has wild char
    v:120918,120828,120209\s.zaglio: #files.size to bigint;added option *;remove #objs
    v:120112\s.zaglio: added read of format date from registry
    v:120111\s.zaglio: adapted to new #files format and a remake
    v:111103\s.zaglio: used fn__ntext_to_lines and dir when english settings
    v:110316\s.zaglio: adapted to last sp__write_ntext_to_lines upd
    v:100919.1115,100919.1100\s.zaglio: compatible with mssql2k;added special syntax
    v:100919.1000\s.zaglio: a bug in list of db objs and added out to #files
    v:100509,100508\s.zaglio: added @subdir;added DR flag and directory distinction
    v:100410,100405,100402\s.zaglio: added db search;added @out;a remake
    t:sp__dir ''*str*'',@dbg=1
    t:sp__dir ''%temp%\*.*'',@dbg=1
    t:sp__dir ''c:\*.ini'',@opt=''s'',@dbg=1    -- 16 sec by cmdline, 18 by sp
    t:sp__dir @opt=''*'',@path=''util''
    t:job
    t:sp__dir ''\\lupin\tecnico\_SCRIPTS\SINTESI\3\3.02''
*/
CREATE proc [dbo].[sp__dir]
    @path   nvarchar(512)   =null,
    @isql   nvarchar(1024)  =null,
    @opt    sysname         =null,
    @dbg    int             =0
as
begin
set nocount on
declare @proc sysname,@ret int
select  @proc=object_name(@@procid),@ret=0,
        @opt=dbo.fn__Str_quote(isnull(@opt,''''),''|'')

declare
    @cmd nvarchar(4000),@d datetime,
    @db sysname,@sch sysname,@obj sysname,
    @sql nvarchar(4000),@file nvarchar(4000),
    @n int,@i int, @path_ex sysname,
    @top sysname,@oby sysname,
    @psep nvarchar(2),@dsep nvarchar(2),
    @fmt sysname,@select bit,@grp bit,@s bit,
    @blob varbinary(max),@text nvarchar(max),
    @start int,@end int,@dir nvarchar(4000),
    @lng char,@rid int,@files_id int,
    @kp bit                         -- keep path in name

declare @obj_order table(xt varchar(4),ord tinyint)

insert @obj_order
select ''u'',10 union
select ''tr'',15 union
select ''p'',20 union
select ''v'',30 union
select ''if'',40 union
select ''tf'',50 union
select ''fn'',60 union
select ''sn'',70 union
select ''pk'',80 union
select ''f'',90 union
select ''d'',100

select
    @files_id=isnull(object_id(''tempdb..#files''),0),
    @dsep='':'',
    @select=charindex(''|select|'',@opt)|charindex(''|sel|'',@opt),
    @grp=charindex(''|grp|'',@opt),
    @s=charindex(''|s|'',@opt)|charindex(''|sub|'',@opt),
    @kp=charindex(''|kp|'',@opt)|1-@select|1-cast(@files_id as bit),
    @psep=psep,
    @path=case charindex(''|*|'',@opt)
          when 0
          then @path
          else replace(@path,''#'',''*'')+''*''
          end,
    -- full search
    @path_ex=case charindex(''|*|'',@opt)
           when 0 then ''''
           else ''*''+replace(@path,''#'',''*'')+''*''
           end
from fn__sym()

if left(@path,4)=''grp:'' select @grp=1,@path=substring(@path,5,len(@path)-4)

declare @stdout table (lno int identity primary key,line nvarchar(4000))

declare @dirs table(s int,e int,dir nvarchar(4000))

declare @files table (
    id int identity primary key,
    [key] nvarchar(446),sdt nvarchar(32),dt datetime,
    sfsize nvarchar(64) null ,n bigint null, flags smallint,
    rid int null
    )

declare @objs table (
    id int identity primary key,
    obj sysname,
    xtype nvarchar(2)
    )

if @path is null goto help

create table #src(lno int identity primary key,line nvarchar(4000))

if @grp=1
    begin
    select
        *
    from fn__script_info(default,''g'',0)
    where cast(val1 as sysname) like replace(@path,''*'',''%'')
    goto ret
    end

-- =========================================================== list from disk ==

if charindex(@dsep,@path)>0 or charindex(@psep,@path)>0
    begin

    -- temp file for output of dir
    exec sp__get_temp_dir @file out
    select @file=@file+@psep+replace(convert(sysname,newid()),''-'',''_'')

    if @dbg>0 exec sp__elapsed @d out

    -- this is the faster method found
    select @cmd =''cmd /u /c dir /4''+case @s when 1 then ''/s'' else '''' end
                                   +'' "''+@path+''" >''+@file+''.txt'' -- 11 secs x 250000
                                   +'' 2>''+@file+''.err''
    if @dbg>1 exec sp__printf ''%s'',@cmd
    delete from @stdout
    insert @stdout exec master..xp_cmdshell @cmd
    select @sql=null
    select top 1 @sql=line from @stdout where line is not null
    if not @sql is null goto err_dir

    if @dbg>0
        exec sp__elapsed @d out,''-- dir&err listed into %s in '',@v1=@file

-- ======================================================= load and split txt ==

    select @blob=null,@text=null
    select @sql=''select @blob=BulkColumn ''
               +''from openrowset(bulk ''''''+@file+''.txt'''', single_blob) as x''
    exec sp_executesql @sql,N''@blob varbinary(max) out'',@blob=@blob out

    select @text=cast(@blob as nvarchar(max))

    if @dbg>0 exec sp__elapsed @d out,''-- file TXT readed into memory''

    if @@error<>0
        exec sp__printf ''%s'',''>>> If error 4861, see http://msdn.microsoft.com/en-us/library/ms188365.aspx''

    truncate table #src
    insert #src(line) select line from fn__ntext_to_lines(@text,0)
    -- 111102\s.zaglio:deprecated sp__write_ntext_to_lines

    if @dbg>0 exec sp__elapsed @d out,''-- TXT splitted into lines''

    if @dbg>1
        begin
        select ''#src'' [#src],* from #src
        exec sp__elapsed @d out,''-- after show of #src''
        end

-- ======================================================= load and split err ==

    select @blob=null,@text=null
    select @sql=''select @blob=BulkColumn ''
               +''from openrowset(bulk ''''''+@file+''.err'''', single_blob) as x''
    exec sp_executesql @sql,N''@blob varbinary(max) out'',@blob=@blob out

    select @text=cast(@blob as nvarchar(max))

    if @dbg>0 exec sp__elapsed @d out,''-- file ERR readed into memory''

    if @@error<>0
        exec sp__printf ''%s'',''>>> If error 4861, see http://msdn.microsoft.com/en-us/library/ms188365.aspx''

    delete from @stdout
    insert @stdout(line) select line from fn__ntext_to_lines(@text,0)
    -- 111102\s.zaglio:deprecated sp__write_ntext_to_lines

    if @dbg>0 exec sp__elapsed @d out,''-- ERR splitted into lines''

    if @dbg>1 select ''stdout'' [stdout],* from @stdout
    select @sql=null
    select top 1 @sql=line from @stdout where line is not null
    if not @sql is null goto err_dir

-- ======================================================== delete temp files ==

    select @cmd=''del /q ''+@file+''.txt&del /q ''+@file+''.err''
    exec master..xp_cmdshell @cmd,no_output

-- ======================================================== split directories ==

    -- t:sp__dir ''c:\*.ini'',@opt=''s|select'' ,@dbg=1
    -- t:sp__dir ''c:\*.ini'',@opt=''s'' ,@dbg=1
    -- t:''sp__dir ''''i:\temp\*'''',@opt=''''s'''',@dbg=1''
    -- t:''sp__dir ''''c:\*.ini'''',@opt=''''s'''',@dbg=1''
    select @n=1
    if @s=0
        begin
        insert @dirs
        select min(lno),max(lno),
               case @kp when 1 then @path else '''' end from #src
        goto skip_with
        end

    -- mssql 2k5 do not support with under if
    ;with dirs(lno,dir) as (
        select lno,right(line,charindex('' '',reverse(line),
                                        len(line)-charindex(@psep,line))-1
                        ) dir
        from #src where line like '' %directory %''+@psep+''%''
        )
    insert @dirs(s,e,dir)
    select
        s.lno+1 s_lno,
        isnull((select top 1 lno from dirs e where e.lno>s.lno),
               (select max(lno) from #src))-1
        as e_lno,
        s.dir
    from dirs s
    select @n=@@rowcount
    if @dbg>0 exec sp__elapsed @d out,''-- %d direcotries'',@v1=@n

skip_with:

    if @dbg>0 exec sp__elapsed @d out,''-- tmp file deleted and split or dirs''

-- ============================================================= check region ==

    -- get local date format
    exec master.. xp_regread
            ''HKEY_CURRENT_USER'',''Control Panel\International'',
            ''sShortDate'',
            @fmt out
    -- or by cmd: REG QUERY "HKCU\Control Panel\International" /v sShortDate&
    -- exec master..xp_regenumvalues ''HKEY_CURRENT_USER'',''Control Panel\International''
    -- GRANT EXECUTE ON sys.xp cmdshell TO [BUILTIN\Users];

    /*  old solution by inspecting content
    if exists(
        select top 1 line
        from #src
        where substring(line,19,2) in (''PM'',''AM'') -- english setting
        )
        select @eng=1
    else
        select @eng=0
    */
    if @fmt like ''d%/m%/y%'' select @lng=''I''
    if @fmt like ''m%/d%/y%'' select @lng=''E''
    if @lng is null goto err_fmt

-- ====================================================== list files with dir ==

    -- 18 by sp, 17 without fn__dir_parse_list
    declare cs cursor local for
        select s,e,dir
        from @dirs
        where 1=1
    open cs
    while 1=1
        begin

        fetch next from cs into @start,@end,@dir
        if @@fetch_status!=0 break

        select @rid=0
        insert @files(rid,sdt,sfsize,[key])
        select @rid,sdt,sfsize,case @kp when 1 then @dir+''\''+name else name end
        from #src cross apply fn__dir_parse_list(line,@lng)
        where line like ''[0-9]%''
        and not line like ''%.''
        and not line is null
        and lno between @start and @end

        end -- cursor cs
    close cs
    deallocate cs

    if @dbg>2 select ''@files'' [@files],* from @files

    -- convert strings
    update @files set
        [n]=case
            when isnumeric(sfsize)=1
            then convert(bigint,sfsize)
            else null
            end,
        [dt]=convert(datetime,sdt),
        flags=case when sfsize='''' then 32 else 0 end

    select @n=@@rowcount
    if @dbg>0 exec sp__elapsed @d out,''-- %d files parsed in'',@v1=@n

    if @dbg>2 select top 100 ''top 100 upd'' step,* from @files

    if @files_id=0 or charindex(''|*|'',@opt)>0
        begin
        if @select=1
            select
                [key] as path,
                flags,
                dt as creation_date,
                n as bytes
            from @files
            -- order by rid,[key]
        else
            begin
            -- insert #files([key],flags,dt,n)
            select id,[key],flags,dt,n
            into #files
            from @files
            -- order by rid,[key]
            exec sp__select_astext ''
                select
                    dt as creation_date,n as bytes,flags,[key] as path
                from #files
                order by path''
            end
        end
    else
        begin
        insert #files([key],flags,dt,n)
        select [key],flags,dt,n from @files
        -- create an index on name
        if not exists(
            select null from tempdb..sysindexes
            where id=@files_id and name=''#ix_files''
            )
            create index #ix_files on #files(rid,[key])
        end

    end     -- list files

-- ============================================================= list objects ==

else

    begin
    select @path=replace(@path,''_'',''[_]'')
    select @path=replace(@path,''%'',''[%]'')
    select @path=replace(@path,''?'',''_'')
    select @path=replace(@path,''*'',''%'')

    select @path_ex=replace(@path_ex,''_'',''[_]'')
    select @path_ex=replace(@path_ex,''%'',''[%]'')
    select @path_ex=replace(@path_ex,''?'',''_'')
    select @path_ex=replace(@path_ex,''*'',''%'')

    -- sp__dir @opt=''*'',@path=''file''
    -- exec sp__printf ''p:%s, e:%s'',@path,@path_ex
    -- sp__dir ''rep*'',''print ''''%obj%''''''

    insert @objs(obj,xtype)
    select [name],xtype
    from sysobjects
    where [name] like @path
    or [name] like @path_ex
    order by 2,1

    if isnull(@isql,'''')!=''''
        begin
        insert #src(line)
        select replace(@isql,''%obj%'',obj)
        from @objs
        order by isnull(
                    (select ord from @obj_order where xt=xtype),
                    ascii(xtype)
                 ), obj
        if @select=1 select line from #src order by lno
        else exec sp__print_table ''#src''
        end
    else
        begin
        if object_id(''tempdb..#files'') is null or charindex(''|*|'',@opt)>0
            begin
            if @select=1
                select * from @objs
                order by isnull(
                            (select ord from @obj_order where xt=xtype),
                            ascii(xtype)
                         ), obj
            else
                begin
                select identity(int,1,1) id,obj,xtype
                into #objs
                from @objs
                order by isnull(
                            (select ord from @obj_order where xt=xtype),
                            ascii(xtype)
                         ), obj

                exec sp__select_astext ''select * from #objs order by 1''
                drop table #objs
                end
            end
        else
            insert #files([key],flags)
            select
                obj,
                convert(smallint,cast(cast(xtype as varchar(2)) as binary(2)))
            from @objs
        end -- !@isql

    -- select @db=db,@sch=sch,@obj=obj from dbo.fn__parsename(@what,0,1)
    end -- db objs

dispose:
drop table #src
-- #files is dropped by engine
goto ret
-- =================================================================== errors ==
err_fmt:    exec @ret=sp__err ''unknown date setting %s'',@proc,@p1=@fmt goto ret
err_dir:    exec @ret=sp__err ''%s'',@proc,@p1=@sql                      goto ret
-- ===================================================================== help ==

help:
exec sp__usage @proc,''
Scope
    list objects or files of a db or dir
    (sp__ftp uses the same #files format)

Notes
    I normally associate this SP to CTRL+4 as "sp__dir @opt=''''*'''',@path="

Parameters
    @path   can be a dir path or name of object of db
            store the list into #files if exists
            accept wild card *,? for both objects
            if begin with "grp:" or grp option is specified,
            search into group names of db objects

            create table #files (
                id int identity primary key,
                rid int default(0),     -- for subdirs
                [flags] smallint,       -- if &32=32 is a 
                [key] nvarchar(446),    -- obj name
                dt datetime,            -- creation date
                n bigint null           -- size in bytes
                )

    @isql   macro code that is printed instead of list where %obj% were replaced
    @opt    options
            *       consider automtically @path as "@path% or %[_]@path%"
                    to attach to a shortkey of SSMS; # can used as jolly char
            select  select instead of print results
            grp     see @path parameter info
            s       same as /s of dir, run recursivelly into sub directories
            sub     alias of option s
            kp      keep path in name (key)
    @dbg    1   show base info and statistics
            2   show also internal tables content

Notes
    where bytes is null, there is a 
    and index #ix_files will created on rid,key

Examples
    exec sp__dir ''''c:\test_if_exists''''

    create table #files ...
    exec sp__dir ''''c:\'''',@dbg=1
    select * from #files
    drop table #files

''
-- ===================================================================== exit ==

ret:

return @ret
end -- sp__dir'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__dir:

-- ======================================================== sp__dir_base_objects
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__dir_base_objects',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=090124
        begin
        if @aut!='S.Zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__dir_base_objects') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__dir_base_objects') with nowait
        goto skip_sp__dir_base_objects
        end
    if @ver>090124
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__dir_base_objects') with nowait
        goto skip_sp__dir_base_objects
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__dir_base_objects') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__dir_base_objects'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__dir_base_objects]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:090124\S.Zaglio: list objects grouped by roots
*/
create proc sp__dir_base_objects
as
select a,b,c from
(
 select
    o.name,dbo.fn__str_at(o.name,''__'',1)+''_'' as a,
    dbo.fn__str_at(dbo.fn__str_at(o.name,''__'',2),''_'',1) as b,
    coalesce(dbo.fn__str_at(dbo.fn__str_at(o.name,''__'',2),''_'',2),'''') as c
 from sysobjects o
 where o.xtype in (''P'',''FN'',''U'',''V'') and left(o.name,3)!=''dt_'' -- and left(o.name,4)=''fn__''
) a
group by a,b,c
having c!=''''
union
select a,b,c from
(
 select
    o.name,
    dbo.fn__str_at(o.name,''_'',1) as a,
    substring(o.name,len(dbo.fn__str_at(o.name,''_'',1))+2,4000) as b,
    '''' as c
 from sysobjects o
 where o.xtype in (''P'',''FN'',''U'',''V'') and left(o.name,3)!=''dt_'' and not o.name like ''%[_][_]%''
) a
group by a,b,c
--having c!=''''
order by a,b,c'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__dir_base_objects:

-- ====================================================== sp__displayoaerrorinfo
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__displayoaerrorinfo',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=000000
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__displayoaerrorinfo') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__displayoaerrorinfo') with nowait
        goto skip_sp__displayoaerrorinfo
        end
    if @ver>000000
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__displayoaerrorinfo') with nowait
        goto skip_sp__displayoaerrorinfo
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__displayoaerrorinfo') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__displayoaerrorinfo'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__displayoaerrorinfo]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:000000\s.zaglio:used by sp_displaypkgerrors,execute_dts,run_dts
*/
CREATE  PROC sp__displayoaerrorinfo
    @object as int,
    @hr as int=0
AS

DECLARE @output nvarchar(255)
DECLARE @source nvarchar(255)
DECLARE @description nvarchar(255)

PRINT ''OLE Automation Error Information''

EXEC @hr = sp_OAGetErrorInfo @object, @source OUT, @description OUT
IF @hr = 0
    BEGIN
        SELECT @output = '' Source: '' + @source
        PRINT @output
        SELECT @output = '' Description: '' + @description
        PRINT @output
    END
ELSE
    BEGIN
        PRINT '' sp_OAGetErrorInfo failed.''
        RETURN
    END'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__displayoaerrorinfo:

-- ======================================================== sp__displayPKGErrors
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__displayPKGErrors',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=091018
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__displayPKGErrors') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__displayPKGErrors') with nowait
        goto skip_sp__displayPKGErrors
        end
    if @ver>091018
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__displayPKGErrors') with nowait
        goto skip_sp__displayPKGErrors
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__displayPKGErrors') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__displayPKGErrors'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__displayPKGErrors]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:091018\s.zaglio: display errors from spExecuteDTS execution
*/
CREATE PROC sp__displayPKGErrors
    @oPkg As integer
AS

SET NOCOUNT ON

DECLARE @StepCount int
DECLARE @Steps int
DECLARE @Step int
DECLARE @StepResult int
DECLARE @oPkgResult int
DECLARE @hr int

DECLARE @StepName nvarchar(255)
DECLARE @StepDescription nvarchar(255)

IF OBJECT_ID(''tempdb..#PkgResult'') IS NOT NULL
        DROP TABLE #PkgResult

CREATE TABLE #PkgResult
(
    StepName nvarchar(255) NOT NULL,
    StepDescription nvarchar(255) NOT NULL,
    Result bit NOT NULL
)

SELECT @oPkgResult = 0

EXEC @hr = sp_OAGetProperty @oPkg, ''Steps'', @Steps OUTPUT
IF @hr <> 0
BEGIN
        PRINT ''***  Unable to get steps''
        EXEC sp__displayoaerrorinfo @oPkg , @hr
        RETURN 1
END

EXEC @hr = sp_OAGetProperty @Steps, ''Count'', @StepCount OUTPUT
IF @hr <> 0
BEGIN
        PRINT ''***  Unable to get number of steps''
        EXEC sp__displayoaerrorinfo @Steps , @hr
        RETURN 1
END

WHILE @StepCount > 0
BEGIN
    EXEC @hr = sp_OAGetProperty @Steps, ''Item'', @Step OUTPUT, @StepCount
    IF @hr <> 0
    BEGIN
            PRINT ''***  Unable to get step''
            EXEC sp__displayoaerrorinfo @Steps , @hr
            RETURN 1
    END

    EXEC @hr = sp_OAGetProperty @Step, ''ExecutionResult'', @StepResult OUTPUT
    IF @hr <> 0
    BEGIN
            PRINT ''***  Unable to get ExecutionResult''
            EXEC sp__displayoaerrorinfo @Step , @hr
            RETURN 1
    END


    EXEC @hr = sp_OAGetProperty @Step, ''Name'', @StepName OUTPUT
    IF @hr <> 0
    BEGIN
            PRINT ''***  Unable to get step Name''
            EXEC sp__displayoaerrorinfo @Step , @hr
            RETURN 1
    END

    EXEC @hr = sp_OAGetProperty @Step, ''Description'', @StepDescription OUTPUT
    IF @hr <> 0
    BEGIN
            PRINT ''***  Unable to get step Description''
            EXEC sp__displayoaerrorinfo @Step , @hr
            RETURN 1
    END

    INSERT #PkgResult VALUES(@StepName, @StepDescription, @StepResult)
    PRINT ''Step '' + @StepName + '' ('' + @StepDescription + '') '' + CASE WHEN @StepResult = 0 THEN ''Succeeded'' ELSE ''Failed'' END

    SELECT @StepCount = @StepCount - 1
    SELECT @oPkgResult = @oPkgResult + @StepResult
END

SELECT * FROM #PkgResult

IF @oPkgResult > 0
BEGIN
    PRINT ''Package had '' + CAST(@oPkgResult as nvarchar) + '' failed step(s)''
    RETURN 9
END
ELSE
BEGIN
    PRINT ''Packge Succeeded''
    RETURN 0
END'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__displayPKGErrors:

-- ==================================================================== sp__drop
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__drop',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120802
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__drop') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__drop') with nowait
        goto skip_sp__drop
        end
    if @ver>120802
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__drop') with nowait
        goto skip_sp__drop
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__drop') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__drop'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__drop]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:120802\s.zaglio: added drop of tbl.col
    v:110331\s.zaglio: removed use of fn__locked
    v:101112\s.zaglio: a bug near deleting tables in tempdb that''s not #temp tables
    v:100919\s.zaglio: added order by name desc to manage 1/2 problems with fkeys
    v:100718\s.zaglio: a total remake of old, to delete files,temps,any obj without errors
    t:
        declare @sql nvarchar(4000)
        select @sql=''
            create table drop_test1(a int)
            create table drop_test2(a int)
            create table drop_test3(a int)
            create table #drop_test4(a int)
            ''

        exec(@sql)  exec sp__printf ''multiple test''
        exec sp__drop ''drop_test1|drop_test2|drop_test3|#drop_test4''
        exec sp__dir ''drop_test*''

        exec(@sql)  exec sp__printf ''wild test''
        exec sp__drop ''drop_test*'',@dbg=1
        exec sp__dir ''drop_test*''
        exec sp__drop ''#drop_test4|drop_test*'',@simul=0
        exec sp__dir ''drop_test*''
        exec sp__drop ''#drop_test4'',@dbg=1
        select * from #drop_test4
*/
CREATE proc [dbo].[sp__drop]
    @names  nvarchar(4000)=null,
    @xtype  nvarchar(2)=null,
    @simul  bit=null,
    @opt    sysname=null,
    @dbg    int=null
as
begin
set nocount on
declare @proc sysname,@ret int
select
    @proc=object_name(@@procid),@ret=0,@dbg=isnull(@dbg,0),
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

if @names is null goto help
if @names=''*'' goto err_no

declare
    @i int,@n int,
    @obj nvarchar(512),@db sysname,@xt nvarchar(4),
    @sql nvarchar(4000),@sch sysname,
    @col sysname

-- select * from tempdb..sysobjects where name like ''%objs%'' and xtype=''u''
-- drop table #sp__drop_objs
create table #sp__drop_objs(
    id int identity,
    db sysname null,sch sysname null,
    obj nvarchar(512),
    col sysname null,
    xt nvarchar(4) null
    )


-- =================================== fill temp table with names

-- declare @names nvarchar(4000) select @names=''#t|[#tt]|here|[test]|[db].dbo.[test]|c:\test.txt|sintesi_vi00*|#sp__drop_objs''
-- declare @names nvarchar(4000) select @names=''drop_test3''
if charindex(''|'',@names)>0
    insert #sp__drop_objs(obj) select token from dbo.fn__str_params(@names,''|'',default)
else
    insert #sp__drop_objs(obj) select @names


-- =================================== update with db info & normalize name
update #sp__drop_objs set
    db= case
        when left(obj,1)=''#'' or left(obj,2)=''[#''
        then ''tempdb''
        when left(obj,1)!=''['' and (obj like ''%[\:/]%'')
        then '''' -- a file
        else isnull(parsename(obj,3),db_name())
        end,
    obj=case
        when left(obj,1)=''#'' or left(obj,2)=''[#''
        then parsename(obj,1)
        when left(obj,1)!=''['' and (obj like ''%[\:/]%'')  -- file
        then obj
        else case
             when charindex(''*'',obj)>0                  -- multiobj
             then replace(replace(parsename(obj,1),''_'',''[_]''),''*'',''%'')
             else
                case -- tbl.col
                when not object_id(parsename(obj,2),N''U'') is null
                then obj
                else parsename(obj,1)
                end
             end
        end

if exists(select null from #sp__drop_objs where obj in (''*'',''sp__drop'')) goto err_no


-- =================================== update with schema and type info from each db

-- declare @i int,@n int,@obj nvarchar(512),@db sysname,@sql nvarchar(4000),@dbg bit,@simul bit set @dbg=1
select @i=min(id),@n=max(id) from #sp__drop_objs
while (@i<=@n)
    begin
    select @db=db,@obj=obj from #sp__drop_objs where id=@i

    if charindex(''.'',@obj)>0
        begin
        select @col=parsename(@obj,1),@obj=parsename(@obj,2)
        select @sql =''alter table ''+quotename(@obj)+'' drop constraint ''
        select @sql = @sql + (select sys_obj.name as constraint_name
        from sysobjects sys_obj
        join syscomments sys_com on sys_obj.id = sys_com.id
        join sysobjects sys_objx on sys_obj.parent_obj = sys_objx.id
        join sysconstraints sys_con on sys_obj.id = sys_con.constid
        join syscolumns sys_col on sys_objx.id = sys_col.id
        and sys_con.colid = sys_col.colid
        where
        sys_obj.uid = user_id() and sys_obj.xtype = ''d''
        and sys_objx.name=@obj and sys_col.name=@col)
        if @dbg=0 exec(@sql) else exec sp__printsql @sql

        if exists(
            select null
            from syscolumns
            where id=object_id(@obj) and name=@col
            )
            begin
            select @sql =''alter table ''+quotename(@obj)
                        +'' drop column ''+quotename(@col)
            if @dbg=0 exec(@sql) else exec sp__printsql @sql
            end

        select @i=@i+1
        continue
        end -- drop tbl.col

    if @db!='''' -- not a file
    and exists(select null from master..sysdatabases where [name]=@db)
        begin

        if charindex(''%'',@obj)>0
            begin
            select  @simul=coalesce(@simul,1),
                    @sql=''insert #sp__drop_objs(db,sch,obj,xt)
                          select ''''%db%'''',u.[name],o.[name],o.xtype
                          from [%db%]..sysobjects o with (nolock)
                          join [%db%]..sysusers u with (nolock)
                          on o.uid=u.uid
                          where ''''S'''' not in (o.xtype,o.[type])
                          and o.name like ''''%obj%''''
                          order by o.name desc
                          ''
            end
        else
            begin
            if left(@obj,1)=''#''
                select  @sql=''
                              update objs set xt=o.xtype,sch=''''''''
                              from #sp__drop_objs objs
                              join [%db%]..sysobjects o with (nolock)
                              on o.id=object_id(''''%db%..%obj%'''')
                              where objs.id=%id%
                             ''
            else
                select  @sql=''
                              update objs set xt=o.xtype,sch=isnull(u.[name],'''''''')
                              from #sp__drop_objs objs
                              join [%db%]..sysobjects o with (nolock)
                              on o.name=''''%obj%'''' and ''''S'''' not in (o.xtype,o.[type])
                              join [%db%]..sysusers u with (nolock) on o.uid=u.uid
                              where objs.id=%id%
                             ''
            end

        exec sp__str_replace @sql out,''%db%|%obj%|%id%'',@db,@obj,@i
        if @dbg=1 exec sp__printf ''%s'',@sql
        exec(@sql)
        end -- db obj

    select @i=@i+1
    end -- expand

if @dbg=1 exec sp__select_astext ''select * from #sp__drop_objs order by obj''

if @simul=1 exec sp__printf ''-- use @simul=0 when delete multiple objects''


-- =================================== delete

-- declare @i int,@n int,@obj nvarchar(512),@db sysname,@sql nvarchar(4000),@xt sysname
--    declare @dbg bit,@sch sysname,@simul
--    select @dbg=1
select @i=min(id),@n=max(id) from #sp__drop_objs
while (@i<=@n)
    begin
    select @db=db,@sch=sch,@obj=obj,@xt=xt
    from #sp__drop_objs where id=@i
    if @db='''' -- is a file
        begin
        select @obj=dbo.fn__str_quote(@obj,''"'')
        set @sql=''del /q ''+@obj
        if @dbg=1 exec sp__printf @sql
        if @dbg=1 exec master..xp_cmdshell @sql else exec master..xp_cmdshell @sql,no_output
        end
    else
        begin
        if @db!='''' and not @xt is null
            begin
            -- exec sp__printf ''db=%s, sch=%s, obj=%s'',@db,@sch,@obj
            select @sql=
                case when @db!=db_name() and left(@obj,1)!=''#'' then ''use ''+quotename(@db)+'';'' else '''' end+
                ''drop ''+case
                when @xt=''TR''   then ''trigger ''
                when @xt=''SN''   then ''synonym ''
                when @xt=''U''    then ''table ''
                when @xt=''P''    then ''proc ''
                when @xt=''V''    then ''view ''
                when @xt in (''PK'',''UQ'',''F'')     then ''index ''
                when @xt in (''FN'',''IF'',''TF'')    then ''function ''
                else null
                end
                +
                case when @db=''tempdb''
                then quotename(@obj)
                else quotename(@sch)+''.''+quotename(@obj)
                end

            if @dbg=1 or @simul=1 exec sp__printf ''%s'',@sql
            else exec(@sql)

            end -- db obj

        if @sch is null and @xt is null and charindex(''%'',@obj)=0 and @dbg=1
            exec sp__printf ''obj "%s" not found'',@obj
        end -- file/db obj

    select @i=@i+1
    end --- while

drop table [#sp__drop_objs]

goto ret

err_no:     exec @ret=sp__err ''cannot delete all objects or sp__drop itself'',@proc  goto ret

help:

exec sp__usage @proc,''
Scope
    delete objects of any type

Parameters
    @names  can be a single object (with db), a file
            can use * wild chars for group of objs
            can use | to delete multiple objs (obj|obj|file|etc)
            can be a table.column tha has constraints to delete
    @xtypes not used
    @simul  when * is used, this must be specified eual to 1 do act
    @opt    options
''
select @ret=-1

ret:
return @ret
end -- sp__drop'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__drop:

-- ================================================================= sp__elapsed
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__elapsed',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130725
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__elapsed') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__elapsed') with nowait
        goto skip_sp__elapsed
        end
    if @ver>130725
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__elapsed') with nowait
        goto skip_sp__elapsed
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__elapsed') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__elapsed'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__elapsed]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:130725,130724,130605\s.zaglio: +days;refactoring;removed printf deprecated parameters
    v:121012.1155\s.zaglio: excluded sp__elapsed time and changed behaviour for help
    v:111115\s.zaglio: replace %d/s with (null) and added help
    v:110526\s.zaglio: added variant ( at end of @c
    v:090916\s.zaglio: added minutes/secs/ms output format
    v:090629\S.Zaglio: added %t
    v:090626\S.Zaglio: added @v1,@v2,@v3,@v4
    v:090616\S.Zaglio: used sp__printf with force
    v:090122\S.Zaglio: print elapsed ms from @d to now
    c:in the future will calibrate it self to subtract inprocess time
    t:exec sp__elapsed ''2013-07-24T11:34:40.000'',''test(''
*/
CREATE proc [dbo].[sp__elapsed](
    @d datetime=null out,
    @c sysname=null,@ms int=null out,
    @v1 sql_variant=null,@v2 sql_variant=null,
    @v3 sql_variant=null,@v4 sql_variant=null
    )
as
begin
declare @proc sysname -- not set here to save time
declare @now datetime select @now=getdate()
declare @dd int, @hh int, @mm int,@ss int
declare @open nvarchar(1),@close nvarchar(1)
if @d=0
or (@@nestlevel=1 and @d is null) goto help

if not @c is null
    begin
    select @c=replace(@c,''%t'',convert(sysname,getdate(),126))
    -- if not @v1 is null or not @v2 is null or not @v3 is null or not @v4 is null
    select @c=dbo.fn__printf(@c,@v1,@v2,@v3,@v4,null,null,null,null,null,null)
    end

if not @c is null
    if right(@c,1)=''('' select @open='''',@close='')''
    else select @open='':'',@close=''''

if @d is null
    begin
    select @d=@now
    if not @c is null
        exec sp__printf ''%s%s%s%s'',
                        @c,@open,@d,@close
    end
else begin
    select @ms=datediff(ms,@d,@now)
    select @d=@now
    if not @c is null
        begin
        if @ms>86399999 -- days
            begin
            select @dd=@ms/86400000,@ms=@ms%86400000
            select @hh=@ms/3600000,@ms=@ms%3600000
            select @mm=@ms/60000,@ms=@ms%60000
            select @ss=@ms/1000,@ms=@ms%1000
            exec sp__printf ''%s%s%dd %dh %dm %ds %sms%s'',
                            @c,@open,@dd,@hh,@mm,@ss,@ms,@close
            /* if @hh=0 -- but not really necessary to loose perf.
                exec sp__printf ''%s%s24h %dm %ds %sms%s'',
                                @c,@open,@mm,@ss,@ms,@close */
            goto ret
            end
        if @ms>59999 -- mins
            begin
            select @mm=@ms/60000,@ms=@ms%60000
            select @ss=@ms/1000,@ms=@ms%1000
            exec sp__printf ''%s%s%dm %ds %sms%s'',
                            @c,@open,@mm,@ss,@ms,@close
            end
        else if @ms>999 -- secs
            begin
            select @ss=@ms/1000,@ms=@ms%1000
            exec sp__printf ''%s%s%ds %sms%s'',
                            @c,@open,@ss,@ms,@close
            end
        else
            exec sp__printf ''%s%s%dms%s'',
                            @c,@open,@ms,@close
        end
    end
ret:
select @d=getdate() -- to exclude sp__elapsed time
return 0

help:
select @proc=object_name(@@procid)
exec sp__usage @proc,''
Scope
    help trace times of application

Notes
    if run from a sp, work well for back compatibility

Parameters
    @d      is the last datetime elapsed
    @c      is an optional comment (if null do not print nothing)
    @ms     are the ms elapsed from @d
    @v1...  replace %s,%d in @c (use sp__printf)

Examples
    declare @d datetime,@ms int select @d=getdate()
    exec sp__elapsed @d out,@ms=@ms out
    print @ms waitfor delay "00:00:01"
    exec sp__elapsed @d out,"after example"

''

select @d=getdate() -- for compatibility of execution
return -1
end -- sp__elapsed'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__elapsed:

-- =================================================================== sp__email
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__email',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131223.1100
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__email') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__email') with nowait
        goto skip_sp__email
        end
    if @ver>131223.1100
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__email') with nowait
        goto skip_sp__email
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__email') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__email'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__email]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    r:131223.1100\s.zaglio: unified sense of attached data table
    r:130305\s.zaglio: small bug and better help
    r:130106\s.zaglio: added test of sp_email and no more mssql2k compatible
    r:120724\s.zaglio: added @header=1
    r:120723\s.zaglio: added chk err of sp__select_astext
    r:110831\s.zaglio: a bug near @dbg when printing @lbody and removed extra output
    r:110531\s.zaglio: now delete attached files if come from selects
    r:110324\s.zaglio: added chk of html type into lbody
    r:110306\s.zaglio: added faciliy #src in @attach
    r:110213\s.zaglio: a small possible bug near #src and @lbody and expanded to max
    r:100919\s.zaglio: compatibility with mssql2k
    r:100612\s.zaglio: added #src
    r:100404\s.zaglio: added cc,bcc
    r:100403\s.zaglio: managed attach as sql
    r:100228\s.zaglio: send a mail
    t:sp__config ''smtp_server'',''????''  <- specify your smtp server
    t:sp__email ''stefano.zaglio@seltris.it'',''test'',''test''
    t:
        exec sp__email @to=''stefano.zaglio@seltris.it'',@cc=''cc ''
        exec sp__email @to=''stefano.zaglio@seltris.it'',@bcc=''bcc ''
    t:
        create table #src(lno int identity,line nvarchar(4000))
        insert #src select ''line1''
        insert #src select ''line2''
        exec sp__email @to=''stefano.zaglio@seltris.it'',@attach=''#src''
        exec sp__email @to=''stefano.zaglio@seltris.it'',@body=''#src''
        drop table #src
*/
CREATE proc [dbo].[sp__email]
    @to nvarchar(4000) = null,
    @subj nvarchar(4000) = null,
    @body nvarchar(max) = null,
    @from nvarchar(100) = null ,
    @smtp nvarchar(100) = null,
    @attach nvarchar(4000) = null,
    @id int = null out,
    @err nvarchar(4000) = null out,
    @at sysname = null,
    @cc nvarchar(4000) = null,@bcc nvarchar(4000)=null,
    @dbg int=0
    /*********************************************************************

    this stored procedure takes the parameters and sends an e-mail.
    all the mail configurations are hard-coded in the stored procedure.
    comments are added to the stored procedure where necessary.
    references to the cdosys objects are at the following msdn web site:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_messaging.asp

    http://support.microsoft.com/?scid=kb%3ben-us%3b312839&x=8&y=12
    ***********************************************************************/
as
begin
set nocount on
declare @proc sysname,@ret int
select @proc=object_name(@@procid),@ret=0

declare
    @hr int,@imsg int,@cmd varchar(255),
    @src varchar(255),@des varchar(500),
    @i int,@n int,@crlf nchar(2),@bit bit,
    @htmlbody bit,
    @obj nvarchar(4000),@tmp nvarchar(4000),@path nvarchar(512),
    @dt datetime,@ptr varbinary(64),
    @sql nvarchar(4000),
    @sp_email int,                      -- object id for sp_email
    @event int                          -- returned by sp_email

declare
    @temail tinyint,
    @tsubj smallint,@tto smallint,@tbody smallint,@tfrom smallint,
    @tsch smallint,@tattach smallint,@tsts smallint

declare @attachments table(id int identity,[name] sysname,del bit default(0))

/*  an idea...
    obj ''email.subj'',@id=300 --> set sub id
    obj ''email.subj'',@rid=''email id'',@dat1=''subj'',@dat2=''attachments'',@dt=''insert time''
    obj ''email''             --> print below table
*/
select              --  rid         dat1            dat2                dt
    @temail =10,
    @tsubj  =300,   --  email id    subj            attachments         insert time
                    --  sched id    subj (when change and log is on ?)
    @tto    =301,   --  email id    -               to list             insert time
    @tbody  =302,   --  email id    -               body                insert time
    @tfrom  =303,   --  email id    from            -                   insert time
    @tattach=304,   --  email id    file/null       image file/select   insert time
    @tsch   =305,   --  email id    at param        -                   insert time
    @tsts   =306,   --  sched id    status/err nfo  -                   insert time

    @subj   =isnull(@subj,''(no subject)''),
    @body   =isnull(@body,''''),
    @from   =isnull(@from,''noreply@noreply.com''),
    @crlf   =crlf
from dbo.fn__sym()

if @to is null and @id is null goto help

create table #blob(blob image)
declare @stdout table(lno int identity primary key,line nvarchar(4000))
create table #sp__email_tmp(lno int identity primary key,line nvarchar(4000))

if @smtp is null
    begin
    select @smtp=convert(sysname,dbo.fn__config(''smtp_server'',null))
    if @smtp is null goto err_smtp
    end

-- todo: if begin with +, is a wiki text page

-- called by Agent (sp__email @rid=??)
if not @id is null -- is the id of email record
    begin
    goto err_todo
    goto send_email
    end -- reschedule

-- adjust data
if isdate(@at)=1 select @dt=convert(datetime,@at)
if patindex(@at,''%get%date%'')>0
    begin
    select @sql=''set @dt=''+@at
    exec sp_executesql @sql,N''@dt datetime out'',@dt=@dt out
    end

select @to=replace(@to,'','','';'')
select @to=replace(@to,''|'','';'')
select @to=replace(replace(@to,''['',''<''),'']'',''>'')
select @cc=replace(replace(@cc,''['',''<''),'']'',''>'')
select @bcc=replace(replace(@bcc,''['',''<''),'']'',''>'')

if @dbg>0
and (charindex(''@'',@to)=0 or charindex(''@'',isnull(@cc,''@''))=0)
    exec sp__printf ''-- %s: warning, @ absent in @to and/or @cc'',@proc

-- temp file for sql
exec sp__get_temp_dir @path out

if left(dbo.fn__sql_strip(substring(@body,1,32),null),7)=''select ''
    select  @attach=substring(@body,1,4000)+coalesce('';''+@attach,''''),
            @body=''see attachment''

if not object_id(@body) is null or not object_id(''tempdb..''+@body) is null
    begin
    select @obj=@body,@body=null
    if @obj!=''#src''
        begin
        exec sp__select_astext @obj,@out=''#sp__email_tmp'',@header=1
        select @body=isnull(@body,'''')+isnull(line,'''')+@crlf
        from #sp__email_tmp order by lno
        end
    else
        begin try
        exec sp_executesql N''
        select @body=isnull(@body,'''''''')+isnull(line,'''''''')+@crlf
        from #src order by lno'',N''@body nvarchar(max) out,@crlf nvarchar(4)'',
        @body=@body out,@crlf=@crlf
        end try
        begin catch
        -- print error_message()
        goto err_src
        end catch
    end

if substring(@body,1,6)='''' select @htmlbody=1

if @dbg=1
    begin
    exec sp__printf ''-- %s attach:%s'',@proc,@attach
    exec sp__printf ''-- %s body:'',@proc
    exec sp__printsql @body
    end

/*  explore attachments into @attachments and generate temp files to send
    in case there are particular attachments
*/
if not @attach is null
    begin
    -- test if want attach a table,view,sp recordset
    -- if charindex(''.'',@attach)=0 and dbo.fn__exists(@attach,null)=1

    select @i=1,@n=dbo.fn__str_count(@attach,'';'')
    while @i<=@n
        begin
        select @obj=dbo.fn__str_at(@attach,'';'',@i),@i=@i+1
        -- print dbo.fn__str_at(''select from order by t;c:\file'','';'',2)

        if @dbg=1 exec sp__printf ''attaching:%s'',@obj

        if not object_id(@obj) is null or not object_id(''tempdb..''+@obj) is null
            select @obj=''select * from ''+quotename(@obj)
        if left(dbo.fn__sql_strip(left(@obj,32),null),7)=''select ''
            begin   -- attach a result of a query stored into a temp xls file
            select @tmp=@path+''\''+replace(convert(sysname,newid()),''-'','''')+''.htm''
            if @dbg=1 exec sp__printf ''out to:%s'',@tmp
            exec @ret=sp__select_astext @obj,@out=@tmp,@dbg=0,@header=1
            if @ret!=0 goto err_sat
            insert @attachments([name],del) select @tmp,1
            end
        else
            begin -- attach files
            if charindex(''*'',@obj)>0 or charindex(''?'',@obj)>0
                begin   -- multiple files
                select @cmd=''dir /b "''+@obj+''"''
                delete from @stdout
                insert @stdout exec master..xp_cmdshell @cmd
                insert @attachments([name]) select line from @stdout
                end
            else        -- single file
                insert @attachments([name]) select @obj
            end -- attach files

        end -- while

    end -- attach

-- ##########################
-- ##
-- ## SP_EMAIL integration
-- ##
-- ########################################################
-- goto send_email
select @sp_email=object_id(''SP_EMAIL'')
if not @sp_email is null
    begin

    -- the sp_email must have same parameters + @event, all out
    if ((select count(*)+1
         from syscolumns
         where id=object_id(@proc)
        )
        =
        (select count(*)
         -- select [sp_email].*
         from syscolumns [sp_email]
         left join syscolumns [sp__email]
         on [sp__email].id=object_id(@proc)
         and [sp_email].name=isnull([sp__email].name,''@event'')
         where [sp_email].id=@sp_email and [sp_email].isoutparam=1
        )
       )
        begin
        if @dbg=1 exec sp__printf ''-- %s: redirect to sp_email'',@proc
        exec @ret=sp_email
            @event=@event out,
            @to =@to out,
            @subj=@subj out,
            @body=@body out,
            @from=@from out,
            @smtp=@smtp out,
            @attach=@attach out,
            @err=@err out,
            @at=@at out,
            @id=@id out,
            @cc=@cc out,
            @bcc=@bcc out,
            @dbg=@dbg out
        if @event!=0 goto ret
        if @event is null goto err_evt
        if @dbg=1 exec sp__printf ''-- %s: continue from sp_email'',@proc
        end
    else
        begin
        if @dbg=1
            exec sp__printf ''-- %s:sp_email exists but with different sign'',
                            @proc
        end
    end -- sp_email

send_email:

-- if scheduled mail, load all attachment into table
if not @at is null
    begin
    select @i=min(id),@n=max(id) from @attachments
    while (@i<=@n)
        begin
        select @obj=[name] from @attachments where id=@i
        -- load file into blob
        exec sp__file_read_blob @obj,@out=''#blob.blob''
        -- select @tattach,@rid,left(@attach,256),blob from #blob
        truncate table #blob
        select @i=@i+1
        end
    -- exec sp__job @run=''exec sp__email @id=%d'',@at=@at,@p1=@id
    /*
        instead of use sp__job
        better use directly use of jobs proc and schedule a new send after each sent
    */
    end -- load into tmp

--************* create the cdo.message object ************************
select @cmd=''cdo.message''
exec @hr = sp_oacreate @cmd, @imsg out
if @hr <>0 goto err_obj

--***************configuring the message object ******************
-- this is to configure a remote smtp server.
-- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_schema_configuration_sendusing.asp
select @cmd=''configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing").value''
exec @hr = sp_oasetproperty @imsg, @cmd,''2''
if @hr <>0 goto err_obj

-- this is to configure the server name or ip address.
-- replace mailservername by the name or ip of your smtp server.
select @cmd=''configuration.fields("http://schemas.microsoft.com/cdo/configuration/smtpserver").value''
exec @hr = sp_oasetproperty @imsg,@cmd, @smtp
if @hr <>0 goto err_obj

-- save the configurations to the message object.
select @cmd=''configuration.fields.update''
exec @hr = sp_oamethod @imsg, @cmd, null
if @hr <>0 goto err_obj

-- set the e-mail parameters.
select @cmd=''To''
exec @hr = sp_oasetproperty @imsg, @cmd, @to
if @hr <>0 goto err_obj

select @cmd=''CC''
exec @hr = sp_oasetproperty @imsg, @cmd, @cc
if @hr <>0 goto err_obj

select @cmd=''BCC''
exec @hr = sp_oasetproperty @imsg, @cmd, @bcc
if @hr <>0 goto err_obj

select @cmd=''From''
exec @hr = sp_oasetproperty @imsg, @cmd, @from
if @hr <>0 goto err_obj

select @cmd=''Subject''
exec @hr = sp_oasetproperty @imsg, @cmd, @subj
if @hr <>0 goto err_obj

if exists(select null from @attachments)
    begin
    declare @hattach int
    select @i=min(id),@n=max(id) from @attachments
    select @cmd=''AddAttachment''
    while (@i<=@n)
        begin
        select @obj=[name],@bit=del from @attachments where id=@i
        select @hattach=null
        exec @hr = sp_oamethod @imsg, @cmd, @hattach out, @obj, null

        if @bit=1
            begin
            select @sql=''del /q "''+@obj+''"''
            exec master..xp_cmdshell @sql,no_output
            end
        if @hr <>0 goto err_obj

        select @i=@i+1
        end -- while
    end -- attach

-- if you are using html e-mail, use ''htmlbody'' instead of ''textbody''.
if @htmlbody=1 select @cmd=''HTMLBody'' else select @cmd=''TextBody''

exec @hr = sp_oasetproperty @imsg, @cmd, @body
if @hr <>0 goto err_obj

select @cmd=''Send''
exec @hr = sp_oamethod @imsg, @cmd, null
if @hr <>0 goto err_obj

if @dbg=1 exec sp__printf ''-- %s: email sent through "%s"'',@proc,@smtp

exec @hr=sp_oadestroy @imsg
select @imsg=null
if @hr <>0 goto err_obj

dispose:
if not object_id(''tempdb..#sp__email_tmp'') is null drop table #sp__email_tmp
if not object_id(''tempdb..#blob'') is null drop table #blob

goto ret

-- =================================================================== errors ==

err_obj:
exec @hr = sp_oageterrorinfo @imsg, @src out, @des out
select @err=@cmd+'':''+coalesce(@src,'''')+'';''+coalesce(@des,'''')
exec @ret=sp__err @err,@proc
if not @imsg is null exec @hr=sp_oadestroy @imsg
goto ret

err_smtp:
select @sql=''set at least the smtp server with\n''
           +''\tsp__config(''''smtp_server'''',''''???'''')''
exec @ret=sp__err @sql,@proc
select @err=''no smtp server''
goto ret

err_todo:
exec @ret=sp__err ''todo'',@proc
goto ret

err_sat:
exec sp__err ''sp__select_astext error from sp__email'',@proc
goto ret

err_evt:
exec sp__err ''sp_email did not handle @event'',@proc
goto ret

err_src:
exec sp__err ''bad #src format, see help'',@proc
goto ret

-- ===================================================================== help ==

help:
create table #vars (id nvarchar(16),value sql_variant)
insert #vars values(
    ''%smtp_server%'',dbo.fn__config(''smtp_server'',null)
    )
insert #vars values(
    ''%smtp_from%'',coalesce(dbo.fn__config(''smtp_from'',null),@from)
    )

select @tmp=''@event = @event out''
select @tmp=@tmp+'',''+@crlf+''        ''+name+'' = ''+name+'' out''
--select name -- sp__email
from syscolumns
where id=object_id(@proc)
order by colid

exec sp__usage @proc,''
Scope
    Send an email using the CDO.MESSAGE object.

Notes
    before do that, test the presence of SP_EMAIL and call it;
    if SP_EMAIL @event return a non zero value, exit without process
    because means that SP_EMAIL has managed data;
    SP_EMAIL must have same parameters all with out clause;

Parameters:
    @to     destination
    @subj   subject
    @from   by default is noreply@noreply.com
    @smtp   smtp server or ip (see global variables below)
    @err    returned error string by cdo.message.send command
    @at     (todo) schedule time
    @cc     carbon copy
    @bcc    black carbon copy
    @body   can be a text constant or a temp table name or a query
            if is a temp table, the content will be inserted into the body
            if is a query, the content will be attached as a HTML table file
    @attach can be single o multiple files separated by ;
            and wild card *,? are valid
            can be a query or a temp table
    @every  YYYYMMDD.HHmmSS or ... (todo)
    @dbg    not zero, show debug info

Glabal variables:
    With dbo.fn__global_set(''''variable'''',''''value'''')
    can be configured global variables for
        smtp_server     (actual:%smtp_server%)
        smtp_from       (actual:%smtp_from%)

Aids
    create table #src(lno int identity,line nvarchar(4000))
    exec sp_email
        %p1%
'',@p1=@tmp
select @ret=-1
drop table #vars

-- ===================================================================== exit ==

ret:
return @ret
end -- sp__email'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__email:

-- =============================================================== sp__email_job
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__email_job',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=120101
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__email_job') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__email_job') with nowait
        goto skip_sp__email_job
        end
    if @ver>120101
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__email_job') with nowait
        goto skip_sp__email_job
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__email_job') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__email_job'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__email_job]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:deferred,at,time,date
    r:120101\s.zaglio: manage deferred emails
*/
CREATE proc sp__email_job
    @opt sysname = null,
    @dbg int=0
as
begin try
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
-- @@nestlevel is >1 if called by other sp

set nocount on

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @err_msg nvarchar(2000)             -- used before raise

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end
    -- @param=nullif(@param,''''),

-- ============================================================== declaration ==
declare
    -- generic common
    @run bit,
    -- @i int,@n int,                      -- index, counter
    -- @sql nvarchar(max),                 -- dynamic sql
    -- options
    -- @sel bit,@print bit,                -- select and print option for utils
    @end_declare bit

-- =========================================================== initialization ==
select
    -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt),
    @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid)
        |cast(@@nestlevel-1 as bit),        -- when called by parent/master SP
    @end_declare=1

-- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1

-- ======================================================== second params chk ==
if  @run=0 goto help


-- =============================================================== #tbls init ==

-- ===================================================================== body ==

/*
tid         flags   rid         pid     cod         dt
email       type    rply        fwd     null
to                  email       copy    txt
subj                email       copy    txt
body                email       copy    txt
cc                  email       copy    txt
bcc                 email       copy    txt
attach_name         email       copy    file name
attach_body type    attach_name copy    blob
grp         type    grp         email   name
*/

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    manage deferred emails

Notes
    (this is only a memo to not loose the knowledge)
    * the default job plan is 1h

Parameters
    @opt    options
            install     install the job
            list        list pending emails
            run         send pending emails now
            ena         enable the job
            dis         disable the job
            30mi        set plan of job every 30 minutes

Examples
    sp__email_job                       -- show this help

''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end try

-- =================================================================== errors ==
begin catch
-- if @@trancount > 0 rollback -- for nested trans see style "procwnt"

exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__email_job'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__email_job:

-- ===================================================================== sp__err
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__err',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131018
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__err') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__err') with nowait
        goto skip_sp__err
        end
    if @ver>131018
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__err') with nowait
        goto skip_sp__err
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__err') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__err'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__err]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:131018\s.zaglio: better help
    v:130927\s.zaglio: better output when called by exception
    v:130722.1000\s.zaglio: a small bug when under try catch
    v:130606\s.zaglio: a small bug when noerr opt
    v:121209\s.zaglio: changed exception msg format again(**)
    v:121206\s.zaglio: back to version 121002 because more correct call stack
    v:121121\s.zaglio: better help
    v:121118\s.zaglio: changed exception msg format and removed @lang,@tr
    v:121002\s.zaglio: a bug when called for exception
    v:120810\s.zaglio: warn option
    v:120809\s.zaglio: engine exception return
    v:120802\s.zaglio: better help
    v:120731\s.zaglio: added db name on print of @cod
    v:120223\s.zaglio: suppressed log of error
    v:111108\s.zaglio: added @opt and moved @src and and @trap
    v:110526\s.zaglio: refined #ex
    v:110523\s.zaglio: removed #err, added @src
    v:110329\s.zaglio: added print of exception error
    v:100706\s.zaglio: more help
    v:100228\s.zaglio: more help
    r:100223\s.zaglio: added params
    r:100222\s.zaglio: a review
    r:100127\s.zaglio: added more help and direct error raise and raise 20
    v:100117\s.zaglio: manage errors
    todo: test it remotelly
    t:sp__err ''immediate error %s'',''sp__this'',@trap=1
    t:sp__err ''immediate error %s'',''sp__this'',@p1=''test''    -- error(1794031170)
    t:sp__err_old
    t:sp__err_test
*/
CREATE proc [dbo].[sp__err]
    @msg    nvarchar(4000)=null out,
    @cod    sysname=null,
    @p1     sql_variant=null,
    @p2     sql_variant=null,
    @p3     sql_variant=null,
    @p4     sql_variant=null,
    @opt    sysname=null
as
begin
set nocount on
declare @proc sysname,@ret int
select
    @proc=object_name(@@procid),
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

declare
    @crlf nchar(2),@err bit,
    @type smallint,@level int,@n int,
    @trap bit,@src bit,@noerr bit,@ex bit,@warn bit,
    @e_msg nvarchar(4000),
    @db sysname

select
    @db=db_name(),
    @trap=charindex(''|trap|'',@opt),
    @src=charindex(''|src|'',@opt),
    @noerr=charindex(''|noerr|'',@opt),
    @ex=charindex(''|ex|'',@opt)
       |case @msg when ''#ex'' then 1 else 0 end,
    @warn=charindex(''|warn|'',@opt),
    @crlf=crlf,
    @e_msg=''error(%d) "%s" in [%s:%s]'',
    @ret=dbo.fn__crc32(@msg)
from dbo.fn__sym()

select
    @msg=dbo.fn__printf(@msg,@p1,@p2,@p3,@p4,null,null,null,null,null,null)

if @noerr=1 goto ret
if @trap=1 select @level=20 else select @level=16

if (@msg is null and @cod is null and @opt=''||'') goto help

-- select @msg=isnull(@msg,'''')

if @ex=1   -- used in a try catch from mssql2k5
    begin
    -- for compatibiliy with ms2k
    declare @err_message nvarchar(4000);
    declare @err_procedure nvarchar(4000);
    declare @err_severity int;
    declare @err_state int;
    declare @err_number int;
    declare @err_line nvarchar(8);

    select
        @ret=dbo.fn__crc32(''exception''),
        @err_message = isnull(@msg,     -- when redefined by developer
                              isnull(error_message(),''-- msg not specified --'')
                             ),
        @err_severity = case @warn when 1 then 10 else error_severity() end,
        @err_state = error_state(),
        @err_number = error_number(),
        @err_line = error_line(),
        @err_procedure = @db+''.''+isnull(error_procedure(),@cod)
                                     -- not correct when managed

    -- dynamics
    -- sp__err/raiserror -> exception -> exception
    -- error(nnn)        -> calledby  -> calledby

    if @err_message like ''error(%)%[[]%]%''
        select @e_msg=@err_message
    else
        select @e_msg=dbo.fn__printf(
                @e_msg,@ret,@err_message,@err_procedure,@err_line,
                null,null,null,null,null,null)
    if @cod!='''' and @cod!=error_procedure()
        select @e_msg=@e_msg
                     +@crlf
                     +''called by [''+@db+''.''+@cod+'':?]''

    select @e_msg=replace(@e_msg,''%'',''%%'')
    raiserror(@e_msg,@err_severity,@err_state) with nowait
    goto ret
    end -- print of exception error

-- sp__usage ''fn__printf''
if not @cod is null select @cod=@db+''.''+@cod

-- raiserror(''test %s'',10,1)
if @src=1 insert #src(line)
    select dbo.fn__printf(@e_msg,
                          @ret,@msg,@cod,null,
                          null,null,null,null,null,null)


select @msg=isnull(@msg,''''),@cod=isnull(@cod,'''')
raiserror(@e_msg,@level,1,@ret,@msg,@cod,''?'') with nowait

goto ret

help:
exec sp__usage @proc,''
Scope
    Introduce a common error management.

Notes
    raiserror <20 do not break SP execution in VS
    raiserror >10 break execution of SP if execute from step of job

Parameters:
    return  return the crc32 calculated on @msg (without replaces)
            and is the number reporter into ()
            (**) unfortunatelly with try/catch and the use or raiserror,
            we lost msg format so "2143915629" is the crc32 of "exception";
            when old style error management and new exception are mixed,
            the error report can contain stack calls ("called by [...]")
    @msg    the message with macros %s, %d or ''''#ex''''
    @proc   name of caller
    @p1..4  replaces %s, %d into @msg
    @opt    options
            trap    0(default) or 1, break the connection (raiserror >=20)
            src     if 1, store the message into #src before raise
                    #src(lno int identity,line nvarchar(4000))
            ex      print exception info, used into catch in mssql2k5 i.e.
                        begin catch
                            if error_number()!=1205 /*deadlock*/ exec sp__err @opt="ex"
                        end catch
                    message can be overridden:
                        exec sp__err "my msg",@proc,@opt="ex"
            noerr   calc on return code but do not raise error
            warn    replace severity with 10 to show only the error

Examples:

    exec @ret = sp__err ''''test''''

    produce

        Messagge 50000, level 16, state 1, procedure sp__err, row 122
        error(-662733300) "test" in [:?]

    the ? means unknown line number

    exec sp__err ''''test %s'''',''''sp__this'''',@p1=''''personal''''

        Messagge 50000, level 16, state 1, procedure sp__err, row 122
        error(-1628459270) "test personal" in [db.sp__this:line]"

    when caused by an exception, a message can be followed by:

        called by [proc:?]
        called by [proc:?]
        ...
''
select @ret=-1

ret:
return @ret
end -- sp__err'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__err:

-- ================================================================ sp__err_test
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__err_test',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130927
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__err_test') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__err_test') with nowait
        goto skip_sp__err_test
        end
    if @ver>130927
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__err_test') with nowait
        goto skip_sp__err_test
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__err_test') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__err_test'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__err_test]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:sp__err,test,old,style,new,style,try,catch
    r:130927\s.zaglio: test sp__err in various conditions
*/
CREATE proc sp__err_test
    @opt sysname = null,
    @dbg int=0
as
begin
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
-- @@nestlevel is >1 if called by other sp (not correct if called by remote sp)

set nocount on

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @err_msg nvarchar(2000)             -- used before raise

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end
    -- @param=nullif(@param,''''),

-- ============================================================== declaration ==
-- =========================================================== initialization ==
-- ======================================================== second params chk ==
-- =============================================================== #tbls init ==
-- ===================================================================== body ==

select @ret=dbo.fn__crc32(''exception'')
exec sp__printf ''-- "exception" error code:%d'',@ret

exec sp__printf ''-- 1) test new try-catch style with back compatibility''
begin try
raiserror(''this is the raised error (the line position is correct)'',16,1)
end try
begin catch
exec @ret=sp__err @cod=@proc,@opt=''ex''
exec sp__printf ''returned code:%d'',@ret
end catch

exec sp__printf ''-- 2) test new try-catch style with redefined message''
begin try
raiserror(''this is the error'',16,1)
end try
begin catch
exec @ret=sp__err ''redefined message with %d param'',@proc,@p1=''one'',@opt=''ex''
exec sp__printf ''returned code:%d'',@ret
end catch

exec sp__printf ''-- 3) test new try-catch style with "error" strip''
begin try
select @err_msg=''redefined message with %d param''
exec @ret=sp__err @err_msg out,@proc,@p1=''A'',@opt=''noerr''
exec sp__printf ''raising:%s'',@err_msg
raiserror(@err_msg,16,1)
end try
begin catch
exec @ret=sp__err @cod=@proc,@opt=''ex''
exec sp__printf ''returned code:%d'',@ret
end catch

exec sp__printf ''-- 4) inner try''
begin try
    begin try
    select @err_msg=''redefined message with %d param''
    exec @ret=sp__err @err_msg out,@proc,@p1=''A'',@opt=''noerr''
    exec sp__printf ''raising:%s'',@err_msg
    raiserror(@err_msg,16,1)
    end try
    begin catch
    exec @ret=sp__err @cod=@proc,@opt=''ex''
    exec sp__printf ''returned code:%d'',@ret
    end catch
end try
begin catch
end catch

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    [write here a short desc]

Parameters
    [param]     [desc]
    @opt        options
    @dbg        1=last most importanti info/show code without execute it
                2=more up level details
                3=more up ...

Examples
    [example]
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end -- proc sp__err_test'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__err_test:

-- ==================================================================== sp__exec
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__exec',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130308
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__exec') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__exec') with nowait
        goto skip_sp__exec
        end
    if @ver>130308
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__exec') with nowait
        goto skip_sp__exec
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__exec') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__exec'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__exec]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:130308\s.zaglio: better help and info
    v:121202\s.zaglio: better help; added dangerous like check; more options
    v:120611\s.zaglio: added %db% macro
    v:120523\s.zaglio: added @opt and run because sp too dangerouse
    v:101202\s.zaglio: added #objs test
    v:100919.1005\s.zaglio: added fast where
    v:100919\s.zaglio: added use of external #objs
    v:100723\s.zaglio: added %cols%
    v:100619\s.zaglio: added @fromdb,@p1..@p4
    v:100301\s.zaglio: execute a script for each object
    c:replaces old utilities sp__foreach??? into this one
    t:sp__exec ''print "%tbl%"'',@opt=''run'',@dbg=1
    t:sp__exec ''print "[%tbl%].[%tbl_col%]"'',@opt=''run'',@dbg=1
    t:sp__exec ''print "%syn%:%syn_base%"'',@opt=''run'',@dbg=1
    t:sp__exec ''print "%isql%"'',@where=''charindex("_str_","%obj%")>0'',@isql=''print "%obj%(FN,TF)"''
    t:sp__exec ''print "%tbl%:%cols%"'',@opt=''run'',@dbg=1
    t:sp__exec ''print "%db%"'',@opt=''run''
*/
CREATE proc sp__exec
    @sql nvarchar(4000)=null,
    @where nvarchar(4000)=null,
    @isql nvarchar(4000)=null,
    @fromdb sysname=null,
    @p1 sysname=null,
    @p2 sysname=null,
    @p3 sysname=null,
    @p4 sysname=null,
    @opt sysname=null,
    @dbg int=0
as
begin
set nocount on
declare @proc sysname,@ret int
select  @proc=object_name(@@procid),@ret=0,
        @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')
if @sql is null goto help

declare @run bit,@db sysname,@nfo bit,@i int,@j int,@wrn bit

select
    @run=charindex(''|run|'',@opt),
    @nfo=charindex(''|nfo|'',@opt),
    @wrn=charindex(''|wrn|'',@opt),
    @i=patindex(''% like %["''''][%][[]%'',@where),
    @j=patindex(''%][%]["'''']%'',@where),
    @db=db_name()

if @i>0 and @j>@i and @wrn=0 goto err_like

if @where=''#objs''
    begin
    if object_id(''tempdb..#objs'') is null goto err_objs
    select @where=''"%tbl%" in (select obj from #objs)''
    end

if left(@where,6)=''%tbl%=''
    begin
    if charindex('',%col%='',@where)>0
        select @where=''"%tbl%" like "''+substring(dbo.fn__str_at(@where,'','',1),7,4000)+''" and ''
                     +''"%col%" like "''+substring(dbo.fn__str_at(@where,'','',2),7,4000)+''"''
    else
        select @where=''"%tbl%" like "''+substring(@where,7,4000)+''"''
    end

-- declare @sql sysname select @sql=''print "%obj%(u,v)"''
create table #objs_sp__exec(
    id int identity primary key,
    obj sysname,typ nvarchar(2),val sysname null,
    cols nvarchar(4000) null
    )
create table #syns (id int primary key,base sysname)   -- for compatibility with mssql2k
create table #typs (xtype nvarchar(2))
declare @col bit,@tsql nvarchar(4000)
declare @qfromdb sysname,@cols nvarchar(4000),@with_cols bit
select @col=0,@with_cols=0

select @fromdb=coalesce(dbo.fn__sql_unquotename(@fromdb),db_name())
select @qfromdb=dbo.fn__sql_quotename(@fromdb)

if dbo.fn__ismssql2k()=0
    insert #syns
    select [object_id],base_object_name
    from sys.synonyms

declare @prm table (id int,p nvarchar(4000) null)
insert @prm select 1,@sql
insert @prm select 2,@where
insert @prm select 3,@isql

if charindex(''%cols%'',@sql)>0
or charindex(''%cols%'',@isql)>0
    select @with_cols=1

-- check syntax
if exists(select null from @prm
          where charindex(''%obj%'',p)>0)
and not exists(select null from @prm
          where charindex(''%obj%('',p)>0)
    goto err_syn

select
    @tsql=
        substring(
            p,
            charindex(''%obj%('',p)+6,
            charindex('')'',p,charindex(''%obj%('',p))-charindex(''%obj%('',p)-6
            )
from @prm
where charindex(''%obj%('',p)>0

if not @tsql is null
    begin
    insert #typs
    select left(token,2)
    from dbo.fn__str_table(@tsql,'','')
    end

-- remove (t,t,t,...)
update @prm set
    p=left(p,charindex(''%obj%('',p)+4)
     +substring(p,charindex('')'',p,charindex(''%obj%('',p))+1,4000)
where charindex(''%obj%('',p)>0

-- reload adjusted params
select @sql=p   from @prm where id=1
select @where=p from @prm where id=2
select @isql=p  from @prm where id=3


if exists(select null from @prm where charindex(''%tbl%'',p)>0)
    insert #typs select ''U''
if exists(select null from @prm where charindex(''%view%'',p)>0)
    insert #typs select ''V''
if exists(select null from @prm where charindex(''%syn%'',p)>0)
    insert #typs select ''SN''
if exists(select null from @prm
          where charindex(''%col%'',p)>0
          or charindex(''%view_col%'',p)>0
          or charindex(''%tbl_col%'',p)>0
         )
    begin
    select @col=1
    if charindex(''%col%'',@sql)>0
    or charindex(''%col%'',@isql)>0
        insert #typs select ''U'' union select ''V''
    if charindex(''%tbl_col%'',@sql)>0
    or charindex(''%tbl_col%'',@isql)>0
        insert #typs select ''U''
    if charindex(''%view_col%'',@sql)>0
    or charindex(''%view_col%'',@isql)>0
        insert #typs select ''V''

    select @tsql=''
    insert #objs_sp__exec(obj,typ,val,cols)
    select o.[name],o.xtype,c.name,''+
        case when @with_cols=1
             then ''dbo.fn__flds_of(o.[name],'''','''',null)''
             else ''null''
        end+''
    from ''+@qfromdb+''..sysobjects o
    join ''+@qfromdb+''..syscolumns c on c.id=o.id
    left join #syns s on o.id=s.id and o.xtype=''''SN''''
    where o.xtype in (select xtype from #typs)
    order by o.xtype,c.colorder
    ''
    exec(@tsql)

    end -- insert cols
else
    begin
    select @tsql=''
    insert #objs_sp__exec(obj,typ,val,cols)
    select o.[name],o.xtype,s.base,''+
        case when @with_cols=1
             then ''dbo.fn__flds_of(o.[name],'''','''',null)''
             else ''null''
        end+''
    from ''+@qfromdb+''..sysobjects o
    left join #syns s on o.id=s.id and o.xtype=''''SN''''
    where o.xtype in (select xtype from #typs)
    order by o.xtype
    ''
    exec(@tsql)
    end

-- if @dbg=1 exec sp__select_astext ''select * from #objs_sp__exec''

select @sql=replace(@sql,''"'','''''''')
select @where=replace(@where,''"'','''''''')
select @isql=replace(@isql,''"'','''''''')

declare @tkns nvarchar(4000)
select @tkns=''%tbl%|%view%|%syn%|%tbl_col%|%view_col%|%syn_base%|%base%|%col%''

exec sp__str_replace
        @sql out,
        @tkns,
        ''%obj%'',''%obj%'',''%obj%'',''%val%'',''%val%'',''%val%'',''%val%'',''%val%''
if not @isql is null
    exec sp__str_replace
            @isql out,
            @tkns,
            ''%obj%'',''%obj%'',''%obj%'',''%val%'',''%val%'',''%val%'',''%val%'',''%val%''
if not @where is null
    exec sp__str_replace
            @where out,
            @tkns,
            ''%obj%'',''%obj%'',''%obj%'',''%val%'',''%val%'',''%val%'',''%val%'',''%val%''

if not exists(select null from #objs_sp__exec)
and (charindex(''%db%'',@sql)>0 or charindex(''%fromdb%'',@sql)>0)
    insert #objs_sp__exec(obj) select @fromdb

declare @b bit,@obj sysname,@xt nvarchar(2),@val sysname,@n int
select @n=0
declare cs cursor local for
    select obj,typ,val,cols
    from #objs_sp__exec
    order by id
open cs
while 1=1
    begin
    fetch next from cs into @obj,@xt,@val,@cols
    if @@fetch_status!=0 break

    -- if @dbg=1 exec sp__printf ''processing (%s,%s,%s) with (%s)'',@obj,@xt,@val,@sql

    select @b=1
    if not @where is null
        begin
        select @b=0
        select @tsql=''if (''+@where+'') select @b=1''
        exec sp__str_replace
                @tsql out,
                ''%obj%|%xt%|%val%|%fromdb%|%db|'',
                @obj,@xt,@val,@fromdb,@db
        exec sp_executesql @tsql,
            N''@b bit out,@obj sysname,@xt sysname,@val sysname'',
            @b=@b out,@obj=@obj,@xt=@xt,@val=@val
        if @@error!=0 exec sp__printf ''error in where:\n%s'',@tsql
        if @dbg=2 exec sp__printf ''b:%s; sql:%s; @val:%s;'',@b,@tsql,@val
        end

    if @b=1
        begin
        select @tsql=@sql
        if not @isql is null
            select @tsql=replace(@tsql,''%isql%'',replace(@isql,'''''''',''''''''''''))

        -- prepare final sql
        exec sp__str_replace
                @tsql out,
                ''%obj%|%xt%|%val%|%fromdb%|%cols%|%db%'',
                @obj,@xt,@val,@fromdb,@cols,@db

        if not @p1 is null select @tsql=replace(@tsql,''%p1%'',@p1)
        if not @p2 is null select @tsql=replace(@tsql,''%p2%'',@p2)
        if not @p3 is null select @tsql=replace(@tsql,''%p3%'',@p3)
        if not @p4 is null select @tsql=replace(@tsql,''%p4%'',@p4)

        select @n=@n+1

        if @dbg=1 or @run=0
            exec sp__printf ''%s'',@tsql
        else
            begin
            exec(@tsql)
            if @@error!=0 and @dbg=0 exec sp__printf ''-- error in:%s'',@tsql
            end
        end
    end -- loop objs

close cs
deallocate cs

if @n=0 exec sp__printf ''-- no objects match condition; use @dgb 2 to see''

goto ret

-- =================================================================== errors ==
err_syn:
    exec @ret=sp__err ''expected ( after %obj%'',@proc
    goto ret
err_objs:
    exec @ret=sp__err ''#objs not found; see help'',@proc
    goto ret
err_like:
    exec @ret=sp__err ''likes like "%[...]%" are not admitted (see wrn option)'',
                      @proc
    goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    execute script for each object of db

Parameters
    @sql    sql template to execute for each object identified
    @isql   is the inside sql used to replace macro %isql%
    @fromdb to load object name from db different from current
    @dbg    1 cmd will be printed and not executed even if RUN is specified
            2 print search sql
    @p1...  replace %p1%,... after macro
    @where  contain an expression that filter objects trought macros
            can be a fast expression like:
            "#objs"     : become: "%tbl% in (select obj from #objs)"
            %tbl%=...   : become: "%tbl%" like "..."
            Macros
                @obj    object name
                @xt     object type (U,V,...)
                @val    in case of synonyms, is the for clause
                        in other cases is the column name
            Notes
                likes like "%[...]%" are not admitted

Options
    run     since 120523, this sp show code only because is to dangerouse.
            Use this option to run it.
    wrn     skip error of dangerouse like

Macros
    %obj%(t,...)is a replacer for each object of specified type
    %tbl%       is a replacer for tables
    %view%      is a replacer for views
    %syn%       is a replacer for synonym
    %syn_base%  is a replacer for synonym reference
    %col%       is a replacer for columns of view or table
    %cols%      is a replacer for "col1,col2,..." of view or table
    %tbl_col%   is a replacer for [table].[column]
    %view_col%  is a replacer for [table].[column]
    %typ%       is a replacer for type(size)    (TODO)
    %master%    is a replacer for master server name in sync system (TODO)
    %master%    is a replacer for slave  server name in sync system (TODO)
    %isql%      is a replacer for inner sql (param @isql)
    %fromdb%    is a replacer from @fromdb
    %db%        is a replacer for db_name()
    "           is a replacer for double quotes

Each macro enable collection of relative object

Examples
    sp__exec ''''print "%tbl%"'''',@dbg=1
    sp__exec ''''print "[%tbl%].[%tbl_col%]"'''',@dbg=1
    sp__exec ''''print "%sym%:%sym_base%"'''',@dbg=1
    sp__exec ''''print "%isql%"'''',@where=''''charindex("_str_","%obj%")>0'''',@isql=''''print "%obj%(FN,TF)"'''',@dbg=1

Objects types
    AF = funzione di aggregazione (CLR)
    C = vincolo CHECK
    D = DEFAULT (vincolo o valore autonomo)
    F = vincolo FOREIGN KEY
    PK = vincolo PRIMARY KEY
    P = stored procedure SQL
    PC = stored procedure assembly (CLR)
    FN = funzione scalare SQL
    FS = funzione scalare assembly (CLR)
    FT = funzione valutata a livello di tabella assembly (CLR)
    R = regola (tipo obsoleto, autonoma)
    RF = procedura-filtro-replica
    S = tabella di base di sistema
    SN = sinonimo
    SQ = coda di servizio
    TA = trigger DML assembly (CLR)
    TR = trigger DML SQL
    IF = funzione SQL inline valutata a livello di tabella
    TF = funzione valutata a livello di tabella SQL
    U = tabella (definita dall''''utente)
    UQ = vincolo UNIQUE
    V = vista
    X = stored procedure estesa
    IT = tabella interna

''

-- ===================================================================== exit ==
ret:
return @ret
end -- proc sp__exec'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__exec:

-- ============================================================= sp__execute_DTS
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__execute_DTS',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=091018
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__execute_DTS') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__execute_DTS') with nowait
        goto skip_sp__execute_DTS
        end
    if @ver>091018
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__execute_DTS') with nowait
        goto skip_sp__execute_DTS
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__execute_DTS') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__execute_DTS'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__execute_DTS]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:091018\s.zaglio: run dts from code
*/
CREATE   PROC sp__execute_DTS
    @PkgName nvarchar(255),             -- Package Name (Defaults to most recent version)
    @param1 sysname=null,
    @value1 sysname=null,
    @Server nvarchar(255)=null,
    @ServerPWD nvarchar(255) = Null,        -- Server Password if using SQL Security to load Package (UID is SUSER_NAME())
    @IntSecurity bit = 0,            -- 0 = SQL Server Security, 1 = Integrated Security
    @PkgPWD nvarchar(255) = ''''        -- Package Password
AS

/* examples:
    -- for running SQL server security authorization
    spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa''
    --/ or /--
    spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa'', 0

    -- for running SQL server security authorization
    spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa'', 1
*/

SET NOCOUNT ON
/*
    Return Values
    - 0 Successfull execution of Package
    - 1 OLE Error
    - 9 Failure of Package
*/

if @Server is null set @Server=@@servername

DECLARE @hr int, @ret int, @oPKG int, @Cmd nvarchar(1000)

-- Create a Pkg Object
EXEC @hr = sp_OACreate ''DTS.Package'', @oPKG OUTPUT
IF @hr <> 0
BEGIN
    PRINT ''***  Create Package object failed''
    EXEC sp__displayoaerrorinfo @oPKG, @hr
    RETURN 1
END

-- Evaluate Security and Build LoadFromSQLServer Statement
IF @IntSecurity = 0
    SET @Cmd = ''LoadFromSQLServer("'' + @Server +''", "'' + SUSER_SNAME() + ''", "'' + @ServerPWD + ''", 0, "'' + @PkgPWD + ''", , , "'' + @PkgName + ''")''
ELSE
    SET @Cmd = ''LoadFromSQLServer("'' + @Server +''", "", "", 256, "'' + @PkgPWD + ''", , , "'' + @PkgName + ''")''

EXEC @hr = sp_OAMethod @oPKG, @Cmd, NULL

IF @hr <> 0
BEGIN
        PRINT ''***  LoadFromSQLServer failed''
        EXEC sp__displayoaerrorinfo @oPKG , @hr
        RETURN 1
END

-- set parameters
if not @param1 is null begin
    EXEC @hr = sp_OAMethod @oPKG, ''AddGlobalVariable'', @Name = @param1, @Value = @value1
    IF @hr <> 0 PRINT ''Cant Add Global Var''
end




-- Execute Pkg
EXEC @hr = sp_OAMethod @oPKG, ''Execute''
IF @hr <> 0
BEGIN
        PRINT ''***  Execute failed''
        EXEC sp__displayoaerrorinfo @oPKG , @hr
        RETURN 1
END

-- Check Pkg Errors
EXEC @ret=sp__DisplayPkgErrors @oPKG

-- Unitialize the Pkg
EXEC @hr = sp_OAMethod @oPKG, ''UnInitialize''
IF @hr <> 0
BEGIN
        PRINT ''***  UnInitialize failed''
        EXEC sp__displayoaerrorinfo @oPKG , @hr
        RETURN 1
END

-- Clean Up
EXEC @hr = sp_OADestroy @oPKG
IF @hr <> 0
BEGIN
    EXEC sp__displayoaerrorinfo @oPKG , @hr
    RETURN 1
END

RETURN @ret'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__execute_DTS:

-- ================================================================== sp__exists
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__exists',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100919
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__exists') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__exists') with nowait
        goto skip_sp__exists
        end
    if @ver>100919
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__exists') with nowait
        goto skip_sp__exists
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__exists') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__exists'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__exists]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100919\s.zaglio: show help about fn__Exists and can be used to test remote server obj existance
*/
CREATE proc sp__exists
    @dbg bit=0
as
begin
set nocount on
-- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg''
declare @proc sysname,  @ret int -- standard API: 0=OK -1=HELP, any=error id
select @proc=''sp__exists'', @ret=0

-- ========================================================= param formal chk ==
-- ============================================================== declaration ==
-- =========================================================== initialization ==
-- ======================================================== second params chk ==
-- ===================================================================== body ==
-- goto ret
-- =================================================================== errors ==
-- ===================================================================== help ==
help:
exec sp__usage ''fn__exists'',''
Scope
    show usage of fn__exists

Parameters
    @objects    name of obj or
            obj1,obj2,...   test if exists "obj1 and obj2 and ..."
            obj1|obj2|...   test if exists "obj1 or  obj2 or  ..."
                can verify existance of #temp objects
                sp__exists can test on remote servers (TODO)

    @type       can be null for any object or:
            fk  test if exists a foreign key for that object
            fl  meand that objX is a tbl.fld

    @dbg        run tests for all functionality (TODO)

Examples
    create table test_ex1(a int)
    print dbo.fn__exists(''''test_ex1'''',default)      -- 1
    print dbo.fn__exists(''''test_ex1.a'''',''''fl'''')     -- 1
    print dbo.fn__exists(''''test_ex1.notx'''',''''fl'''')  -- 0
    drop table test_ex1
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret

end -- proc sp__exists'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__exists:

-- ================================================================ sp__file_get
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_get',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130906
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_get') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_get') with nowait
        goto skip_sp__file_get
        end
    if @ver>130906
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_get') with nowait
        goto skip_sp__file_get
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_get') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_get'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_get]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    k:get,file,web,ftp,drive,disk,storage,download
    r:130906\s.zaglio: adapting to new fn__parse_url and sp__parse_url
    r:130829\s.zaglio: common call for more specified sp to read/download a file
    t:sp__file_get ''%temp%\utility\index.txt''
*/
CREATE proc sp__file_get
    @uri nvarchar(2048) = null out,
    @var varbinary(max) = null out,
    @out nvarchar(1024) = null,
    @opt sysname = null,
    @dbg int=0
as
begin try
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
-- @@nestlevel is >1 if called by other sp

set nocount on

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @err_msg nvarchar(2000)             -- used before raise

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end
    -- @param=nullif(@param,''''),

-- ============================================================== declaration ==
declare
    -- generic common
    @text bit,
    @i int,@n int,                         -- index, counter
    @sql nvarchar(max),                    -- dynamic sql
    -- options
    -- @sel bit,@print bit,                -- select and print option for utils
    @protocol sysname,
    @uid sysname,
    @pwd sysname,
    @host sysname,
    @port int,
    @path nvarchar(4000),
    @page nvarchar(4000),
    @temp nvarchar(512),
    @end_declare bit

-- =========================================================== initialization ==
exec sp__get_temp_dir @temp out
select
    @uri=replace(@uri,''%temp%'',@temp),
    @text=charindex(''|text|'',@opt),
    @end_declare=1

-- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1

-- ======================================================== second params chk ==
if nullif(@uri,'''') is null goto help

-- =============================================================== #tbls init ==

-- ===================================================================== body ==

-- sp__parse_url_test

select
    @protocol=protocol,
    @uid=uid,
    @pwd=pwd,
    @host=host,
    @path=path,
    @page=page
from fn__parse_url(@uri,default)

if @protocol=''ftp'' raiserror(''ftp not yet supported'',16,1)

if @protocol in (''http'',''https'')
    begin
    if @dbg>0 exec sp__printf ''-- getting via web''
    exec sp__web @uri,@rsp=@sql out
    -- select @sql=replace(@sql,@crlf+@crlf,@crlf)
    end

if @protocol=''file''
    begin
    if @dbg>0 exec sp__printf ''-- reading file %s'',@uri
    -- not the faster but read 2MB in 7 seconds on localmachine

    select @sql=''''
    if @text=1
        begin
        exec sp__file_read_stream @uri,@out=@sql out
        select @var=cast(@sql as varbinary(max))
        end
    else
        begin
        select @sql=''select @var=BulkColumn ''
                   +''from openrowset(bulk ''''''+@path+''\''+@page+'''''',single_clob)''
                   +'' as x''
        exec sp_executesql @sql,N''@var image out'',@var=@var out
        end

    select @n=len(@sql)
    if @dbg>0 exec sp__printf ''-- loaded %d chars'',@n
    end

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    get a file from disk, web or ftp (todo) and store into @var or into
    the file specified by @out

Notes
    if executed from console, show the result, useful for tests

Parameters
    [param]     [desc]
    @uri        uniform resource identifier (see sp__parse_url_test)
    @var        image
    @opt        options
                text    inform the sp that the file is a text file
                        default is a binary file
    @dbg        info level

Examples
    sp__file_get "%temp%\utility\index.txt"
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end try

-- =================================================================== errors ==
begin catch
-- if @@trancount > 0 rollback -- for nested trans see style "procwnt"

exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__file_get'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_get:

-- =============================================================== sp__file_read
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_read',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=100127
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_read') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_read') with nowait
        goto skip_sp__file_read
        end
    if @ver>100127
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_read') with nowait
        goto skip_sp__file_read
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_read') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_read'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_read]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:100127\s.zaglio:deprecated use of fn__inject and sp__readtable
    v:090928\s.zaglio:removed a double cmd execution and added remove of cr
    v:090731\S.Zaglio:added external temp table management
    v:090123\S.Zaglio:renamed old sp__readtextfile andreplaced in other sp
    v:081009\S.Zaglio:added @step
    v:080916\S.Zaglio:added @outputvar
    v:080815\s.zaglio:added @dbg as param and [] around outputable
    v:080414\s.zaglio:removed content variable
*/
CREATE proc [dbo].[sp__file_read]
    @textfilename sysname,
    @outputtable nvarchar(128) = null,
    @outputvar nvarchar(4000) =null out,
    @step int=1,
    @dbg bit=0
as
set nocount on
declare @tmp bit set @tmp=0
if @dbg=1 print ''sp__file_read''
if (@textfilename=''-?'') goto help
if @outputtable is null and @outputvar is null goto help

if @outputtable is null begin
    set @outputtable=''tmp_''+convert(nvarchar(64),newid())
    set @tmp=1
end

if left(@outputtable,1)<>''['' set @outputtable=''[''+@outputtable+'']''
declare @sql nvarchar(4000)
if left(@outputtable,2)<>''[#'' -- if no external temp table generated
    begin
    set @sql=''create table %outputtable% (lno int identity(%step%,%step%), line nvarchar(4000))''
    exec sp__str_replace @sql out,''%outputtable%|%step%'',@outputtable,@step
    if @dbg=1 print @sql
    exec (@sql)
    end

declare @cmd nvarchar(4000), @crlf nchar(2)
set @cmd=''type "''+@textfilename+''"''
set @crlf=char(13)+char(10)
if @dbg=1 print @cmd
-- exec master.dbo.xp_cmdshell @cmd,no_output

set @sql=''insert ''+@outputtable+'' (line)''
set @sql=@sql+'' exec master.dbo.xp_cmdshell ''''''+replace(@cmd,'''''''','''''''''''')+''''''''
if @dbg=1 print @sql
exec(@sql)

if not @outputvar is null
    exec sp__err ''sp__readtable deprecated'',@cod=''sp__file_read''
-- exec sp__readtable @outputtable,@outputvar out,@dbg=@dbg
if @tmp=1 begin
    set @sql=''drop table ''+@outputtable
    exec(@sql)
end
return 0

help:
/*
exec sp_usage @objectname=''sp_readtextfile'',
@desc=''reads the contents of a ntext file into a sql result set'',
@parameters=''@textfilename=name of file to read, @contents=optional output var
to receive contents of file (up to 8000 bytes)'',
@author=''ken henderson'', @email=''khen@khen.com'',
@version=''8'',@revision=''0'',
@datecreated=''19960501'', @datelastchanged=''20000120'',
@example=''sp_readtextfile ''''d:\mssql7\log\errorlog'''' ''
*/
return -1'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_read:

-- ========================================================== sp__file_read_blob
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_read_blob',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131017
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_read_blob') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_read_blob') with nowait
        goto skip_sp__file_read_blob
        end
    if @ver>131017
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_read_blob') with nowait
        goto skip_sp__file_read_blob
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_read_blob') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_read_blob'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_read_blob]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:131017\s.zaglio: about help
    v:121021\s.zaglio: added @opt and option asm with help
    v:100915.1559\s.zaglio: added more help
    v:100228\s.zaglio: load binary file into temp table
    v:100104\s.zaglio: load a binary file a print inserts
    s:sp__write_ntext_to_lines for text blob
    c:originally from www.sql.ru (mythical boys)
    t:
        declare @path varchar(1024),@cmd sysname
        select @path=''c:\windows\system32\findstr.exe''
        select @cmd=''dir "''+@path+''"''
        exec sp__file_read_blob @path,''%temp%\test.bin'',@uid=''uid'',@pwd=''pwd''
    t:
        exec sp__run_cmd ''dir "%SystemRoot%\system32\cmd.exe"'' -- 389120
        create table #blob (blob image)
        exec sp__file_read_blob ''c:\windows\system32\cmd.exe'',@out=''#blob.blob'',@dbg=1
        select datalength(blob) from #blob
        drop table #blob
    t:exec sp__file_read_blob ''c:\windows\system32\cmd.exe'',@opt=''asm''

*/
CREATE proc [dbo].[sp__file_read_blob]
    @path sysname=null,
    @out sysname=null,
    @uid sysname=''null'',
    @pwd sysname=''null'',
    @opt sysname=null,
    @dbg bit=0
as
begin
set nocount on
declare
    @proc sysname,@tmp sysname,@ret int,
    @buffer varbinary (8000),
    @msg nvarchar(4000),
    @adodbstream int,
    @hr int,@size int,@ssize nvarchar(10),
    @file sysname,@cmd sysname,
    @ptr varbinary(64),
    @asm bit,@n int,
    @end_declare bit

select
    @proc=object_name(@@procid),@ret=0,
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'')

if @path like ''%..%'' goto err_wpro

if @path is null goto help

select @tmp=''##blob'' --''[tmp''+replace(convert(sysname,newid()),''-'','''')+'']''

if charindex(''\'',@out)>0 select @file=@out,@out=null
select @asm=charindex(''|asm|'',@opt)

if @out is null select @size=64
else select @size=8000

if @dbg=1 exec sp__printf ''init stream...''

select @ssize=convert(nvarchar(10),@size)
select @cmd=''adodb.stream''
exec @hr = sp_oacreate @cmd, @adodbstream out
if @hr!=0 goto err
select @cmd=''type''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,1
if @hr!=0 goto err
select @cmd=''open''
exec @hr = sp_oamethod  @adodbstream , @cmd, null
if @hr!=0 goto err
select @cmd=''loadfromfile''
exec @hr = sp_oamethod  @adodbstream , @cmd, null, @path
if @hr!=0 goto err
select @cmd=''read''
exec @hr = sp_oamethod  @adodbstream , @cmd, @buffer out, @ssize
if @hr!=0 goto err

if @dbg=1 exec sp__printf ''read chunks...''

if @asm=0
    begin
    if @out is null
        begin
        print ''declare @ptr varbinary(64)''
        print ''create table ''+@tmp+''(blob image)''
        print ''insert ''+@tmp+'' values(''+dbo.fn__hex(convert(varbinary(64),substring(@buffer,1,@size)))+'')''
        print ''select @ptr=textptr(blob) from ''+@tmp
        end
    else
        begin
        if object_id(''tempdb..#blob'') is null goto err_tbl
        insert #blob values (@buffer)
        select @ptr=textptr(blob) from #blob
        end
    end -- !asm

select @n=0
while @buffer is not null
    begin
    select @cmd=''read''
    exec @hr = sp_oamethod  @adodbstream , @cmd, @buffer out, @ssize out

    if @hr!=0 goto err
    -- print dbo.fn__hex(@ptr)
    if @asm=1
        begin
        if @n=0
            select @msg=dbo.fn__hex(convert(varbinary(64),
                                    substring(@buffer,1,@size)))+''\''
        else
            select @msg=substring(dbo.fn__hex(convert(varbinary(64),
                                              substring(@buffer,1,@size))),
                                  3,@size*2)+''\''
        exec sp__printf ''%s'',@msg
        end
    else
        begin
        if @out is null
            begin
            select @msg=dbo.fn__hex(convert(varbinary(64),
                                    substring(@buffer,1,@size)))+''\''
            print ''updatetext ''+@tmp+''.blob @ptr null 0 ''+@msg
            end
        else
            begin
            updatetext #blob.blob @ptr null 0 @buffer
            end
        end -- !asm
    select @n=@n+1
    end --loop

if @dbg=1 select datalength(blob) as dl, blob  as fdata from #blob

if @asm=0
    begin
    if @out is null
        begin
        if not @file is null
            begin
            select @msg =''exec sp__file_write_blob ''''select top 1 blob from %s'''',''+
                        +''''''%s'''',@uid=%s,@pwd=%s''
            exec sp__printf @msg,@tmp,@file,@uid,@pwd
            select @msg=''exec sp__run_cmd ''''fc /b "%s" "%s"''''''
            exec sp__printf @msg,@path,@file
            select @msg=''exec sp__run_cmd ''''dir "%s" & dir "%s"''''''
            exec sp__printf @msg,@path,@file
            select @msg=null
            end
        print ''drop table ''+@tmp
        end
    end -- !asm

goto ret

-- =================================================================== errors ==
err_wpro:   exec @ret=sp__err ''worked protection against hackers :-) '',@proc
            goto ret
err_tbl:    exec @ret=sp__err ''caller must create table #blob(blob image)'',@proc
            goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,N''
Scope
    Load a file into a blob or script it.

Notes
    maybe today is better use one of:
    -- varbinary
    select BulkColumn from openrowset(bulk "%path%", single_blob) as blob
    -- varchar (until 2k12, does not support code page 65001(UTF-8 encoding))
    select BulkColumn from openrowset(bulk "%path%", single_clob) as blob
    -- nvarchar (require BOM)
    select BulkColumn from openrowset(bulk "%path%", single_nclob) as blob

See also
    * sp__file_read_stream

Parameters
    @path   source file
    @out    destination table.blob, file or null
            if null print the script to write
            else with sp__file_write_blob
    @uid    optional when @out is a file
    @pwd    optional when @out is a file
    @opt    options
            asm     script only hex code
    @dbg    1:debug info


Eample:
    create table #blob (blob image)
    exec sp__file_read_blob ''''file_path'''',@out=''''#blob.blob''''
    insert into #mytable(image_fld) select blob from #blob
    ...
''
select @ret=-1
goto ret

err:
declare @source nvarchar(255)
declare @description nvarchar(255)

exec @hr = sp_oageterrorinfo @adodbstream, @source out, @description out
exec @hr = sp_oadestroy @adodbstream
select @adodbstream=null
exec @ret=sp__err ''ole error (%s;%s;%s)'',@proc,@p1=@cmd,@p2=@source,@p3=@description
goto ret

-- ===================================================================== exit ==
ret:
if @adodbstream!=0 exec @hr = sp_oadestroy @adodbstream
set nocount off
return @ret
end -- [sp__file_read_blob]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_read_blob:

-- ======================================================== sp__file_read_stream
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_read_stream',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=130612
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_read_stream') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_read_stream') with nowait
        goto skip_sp__file_read_stream
        end
    if @ver>130612
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_read_stream') with nowait
        goto skip_sp__file_read_stream
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_read_stream') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_read_stream'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_read_stream]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:130612\s.zaglio: @out to null if error
    v:130529\s.zaglio: added out to @out
    v:120406\s.zaglio: replaced #blob with #spfrsblob
    v:110921\s.zaglio: adapted to use of fn__ntext_to_lines
    v:110316\s.zaglio: adapted to new sp__write_ntext_to_lines #blob struct.
    v:100915\s.zaglio: added more help
    v:100603\s.zaglio: caos about line end
    v:100514.1436\s.zaglio: load txt file with different format (utf8, etc.)
    c:
        the filesystem object don''t read utf8 txt files
        the type of cmd do not read utf8
        BULK INSERT #blob FROM ''file.txt'' do not read utf8
    t:
        exec xp_cmdshell ''echo line 1 >%temp%\test.txt''
        exec xp_cmdshell ''echo line 2 >>%temp%\test.txt''
        create table #src(lno int identity,line nvarchar(4000))
        exec sp__file_read_stream ''%temp%\test.txt'',@out=''#src'',@dbg=1
        select * from #src order by lno
        drop table #src
*/
CREATE proc [dbo].[sp__file_read_stream]
    @path nvarchar(512)=null,
    @out nvarchar(max)=null out,
    @fmt sysname=''utf-8'',
    @ls int=-1,
    @uid sysname=''null'',
    @pwd sysname=''null'',
    @dbg bit=0
as
begin
set nocount on
declare
    @proc sysname,@tmp sysname,@ret int,
    @msg nvarchar(4000),--@buffer varchar(4000),
    @adodbstream int,
    @hr int,@size int,@ssize nvarchar(10),
    @chunk nvarchar(4000),
    @file sysname,@cmd sysname,
    @ptr varbinary(64),@n int,
    @end_declare bit

create table #spfrsblob(id int identity,blob ntext null)
insert #spfrsblob(blob) select ''''
select top 1 @ptr=textptr(blob) from #spfrsblob where id=1
if @ptr is null goto err_ptr
-- drop table #buffer

select @proc=object_name(@@procid),@ret=0
if @path is null goto help

if @path like ''%[%]temp[%]%''
    begin
    exec sp__get_temp_dir @tmp out
    select @path=replace(@path,''%temp%'',@tmp)
    if @dbg=1 exec sp__printf ''path:%s'',@path
    end

if @path like ''%..%'' goto err_wpro

select @size=4000

if @dbg=1 exec sp__printf ''init stream...''

select @ssize=convert(nvarchar(10),@size)
select @cmd=''ADODB.Stream''
exec @hr = sp_oacreate @cmd, @adodbstream out
if @hr!=0 goto err
select @cmd=''Type''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,2 -- text
if @hr!=0 goto err
select @cmd=''charset''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,@fmt
if @hr!=0 goto err
select @cmd=''LineSeparator''
exec @hr = sp_oasetproperty  @adodbstream ,@cmd,@ls
if @hr!=0 goto err
select @cmd=''Open''
exec @hr = sp_oamethod  @adodbstream , @cmd, null
if @hr!=0 goto err
select @cmd=''LoadFromFile''
exec @hr = sp_oamethod  @adodbstream , @cmd, null, @path
if @hr!=0 goto err
select @cmd=''ReadText''

while (1=1)
    begin
    select @chunk=null
    exec @hr = sp_oamethod  @adodbstream , @cmd, @chunk out ,@size  -- with @size=.2 means read line
    select @n=len(@chunk)
    if @dbg=1 exec sp__printf ''chunk of %d:%s'',@n,@chunk
    if @hr!=0 goto err
    if @n=0 or @chunk is null break
    updatetext #spfrsblob.blob @ptr null 0 @chunk
    end

if @out is null
    -- exec sp__write_ntext_to_lines @dbg=@dbg
    select line
    from dbo.fn__ntext_to_lines((select top 1 blob from #spfrsblob),0)
    order by lno
else
    begin
    if @out=''#src''
        insert #src(line) select line
        from dbo.fn__ntext_to_lines((select top 1 blob from #spfrsblob),0)
        order by lno
    if @out=''#out''
        insert #out(line) select line
        from dbo.fn__ntext_to_lines((select top 1 blob from #spfrsblob),0)
        order by lno
    if @out=''''
        select top 1 @out=blob from #spfrsblob
    end -- out to know tables

-- drop table #blob

goto ret

help:
exec sp__usage @proc,''
Scope
    Import a text file

Parameters
    @path   source file path
    @out    can be #src or #out or nothing to out as recordset
            if is an empty string '''''''', out to @out itself
    @fmt    is the format of source file; by default is "utf-8"
            Other format are gived from constants acecpted by
            adodb.stream "charset" property.
    @ls     line separator (default -1 for CRLF else 10 for LF or 13 for CR)
            Unfortunatelly, MSSQL generates log that are incompatibile with
            this (or after too many tests I have not found one good)
            In that case the old xp_cmdshell "type ..." work well.

Notes
    BULK INSERT #blob FROM ''''file.txt'''' do not read utf8

See also
    * http://www.w3schools.com/ado/ado_ref_stream.asp
    * sp__write_ntext_to_lines
    * in MS2K5 can use
        select BulkColumn
        from openrowset(bulk ''''file'''',  single_clob) as x
            single_clob     text
            single_nclob    ntext   (not support utf8 and require specific unicode txt file)
            single_blob     image
    * ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.it/tsqlref9/html/f47eda43-33aa-454d-840a-bb15a031ca17.htm

Example
    exec xp_cmdshell ''''echo line 1 >%temp%\test.txt''''
    exec xp_cmdshell ''''echo line 2 >>%temp%\test.txt''''
    create table #src(lno int identity,line nvarchar(4000))
    exec sp__file_read_stream ''''%temp%\test.txt'''',@out=''''#src'''',@dbg=1
    select * from #src order by lno
    drop table #src
''
select @ret=-1
goto ret

err:
declare @source nvarchar(255)
declare @description nvarchar(255)

exec @hr = sp_oageterrorinfo @adodbstream, @source out, @description out
exec @hr = sp_oadestroy @adodbstream
select @adodbstream=null,@out=null
exec @ret=sp__err ''ole error (%s;%s;%s)'',@proc,@p1=@cmd,@p2=@source,@p3=@description
goto ret

err_wpro:   exec @ret=sp__err ''worked protection against hackers :-) '',@proc goto ret
err_ptr:    exec @ret=sp__err ''ptr get error'',@proc goto ret

ret:
if @adodbstream!=0 exec @hr = sp_oadestroy @adodbstream
set nocount off
return @ret
end -- [sp__file_read_stream]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_read_stream:

-- ============================================================== sp__file_write
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_write',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=110523
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_write') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_write') with nowait
        goto skip_sp__file_write
        end
    if @ver>110523
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_write') with nowait
        goto skip_sp__file_write
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_write') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_write'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_write]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:110523\s.zaglio: better debug and partial remake
    v:110415\s.zaglio: better debug
    v:100405\s.zaglio: added proc to sp__err
    v:100402\s.zaglio: removed out to xls on help
    v:100311\s.zaglio: deprecated output to xls,cvs because bcp out txt with xls extension and not binary xls
    v:100228\s.zaglio: more specific help and out to excel if file and with .xls
    v:090928\s.zaglio: added @unicode
    v:090925\s.zaglio: some auto corrections
    v:090123\s.zaglio: rewrited mixing from
    http://www.simple-talk.com/sql/t-sql-programming/reading-and-writing-files-in-sql-server-using-t-sql/
    v:080710/s.zaglio: write a table or a multi-string to a file (replace old sp__writetextfile)
    t:
        -- simple test
        declare @st sysname set @st=''this is a test''+char(13)+char(10)+''hello line 2''
        exec sp__file_write ''%temp%\test.txt'',@text=@st
        exec sp__run_cmd ''type %temp%\test.txt'',@dbg=1

        -- simple test with append
        exec sp__file_write ''%temp%\test.txt'',@text=''opened for append'',@addcrlf=1
        exec sp__file_write ''%temp%\test.txt'',@text=''appended 1'',@append=1,@addcrlf=1
        exec sp__file_write ''%temp%\test.txt'',@text=''appended 2'',@append=1,@addcrlf=1
        exec sp__run_cmd ''type %temp%\test.txt'',@dbg=1
        exec sp__run_cmd ''del /q %temp%\test.txt'',@dbg=1

        -- simple test with table
        create table #src (lno int identity(10,10),line nvarchar(4000))
        exec sp__script ''sp__script'',''#src''
        exec sp__file_write ''%temp%\test.txt'',@table=''#src'',@addcrlf=1,@dbg=1
        exec sp__run_cmd ''type %temp%\test.txt'',@dbg=1
        drop table #src

        -- unicode test (don''t work)
        declare @st sysname set @st=''arabia ?????? lang?''
        exec sp__file_write ''%temp%\test.txt'',@text=@st
        exec sp__run_cmd ''type %temp%\test.txt'',@dbg=1

*/
CREATE proc [dbo].[sp__file_write]
    @file nvarchar(1024)=null out,
    @text nvarchar(4000)=null,
    @table sysname =null,
    @addcrlf bit=0,
    @append bit=0,
    @unicode bit=0,
    @uid sysname=null,
    @pwd sysname=null,
    @dbg bit=0
as
begin -- proc
set nocount on
declare @proc sysname,@ret int,@n int,@i int
select @proc=object_name(@@procid),@ret=0
if @table is null and @text is null and @file is null goto help

-- sp__find ''@table=''
if not @table is null
and not @table in (''#src'',''#out'',''#ftpsrc'',''#htm'',''#html'')
    goto err_tbl

if @dbg=1 exec sp__printf ''-- %s ------------------------------'',@proc

if coalesce(@file,'''')='''' goto err_file

declare
    @cmd nvarchar(4000), @crlf nchar(2), @row nvarchar(4000),
    @sql nvarchar(4000), @tmp sysname, @order nvarchar(512),
    @flds nvarchar(4000),@fldsc nvarchar(4000),
    @olecmd sysname,
    @source nvarchar(255),
    @description nvarchar(255),
    @helpfile nvarchar(255),
    @helpid int

select @crlf = crlf from fn__sym()

declare
    @objfilesystem int,@objtextstream int,@objerrorobject int,
    @strerrormessage nvarchar(1000),@hr int

if charindex(''%temp%'',@file)>0 begin
    exec sp__get_temp_dir @row out
    set @file=replace(@file,''%temp%'',@row)
    if @dbg=1 print @file
end

if left(@file,1)=''"'' select @file=substring(@file,2,4000)
if right(@file,1)=''"'' select @file=left(@file,len(@file)-1)

if not @table is null
    begin
    if @table=''#out''
        declare cs cursor local for
            select line
            from #out
            order by lno
    if @table=''#src''
        declare cs cursor local for
            select line
            from #src
            order by lno
    if @table=''#ftpsrc''
        declare cs cursor local for
            select line
            from #ftpsrc
            order by lno
    if @table=''#htm''
        declare cs cursor local for
            select line
            from #htm
            order by lno
    if @table=''#html''
        declare cs cursor local for
            select line
            from #html
            order by lno
    open cs
    end -- table source

/*
    see: http://msdn.microsoft.com/en-us/library/314cz14s(VS.85).aspx
    object.OpenTextFile(filename[, iomode[, create[, format]]])
    object:Required. Object is always the name of a FileSystemObject.
    filename:Required. String expression that identifies the file to open.
    iomode:Optional. Can be one of three constants: ForReading, ForWriting, or ForAppending.
    create:Optional. Boolean value that indicates whether a new file can be created if the specified filename doesn''t exist. The value is True if a new file is created, False if it isn''t created. If omitted, a new file isn''t created.
    format:Optional. One of three Tristate values used to indicate the format of the opened file. If omitted, the file is opened as ASCII.
    Settings:The iomode argument can have any of the following settings:
         ForReading|1|Open a file for reading only. You can''t write to this file.
         ForWriting|2|Open a file for writing.
         ForAppending|8|Open a file and write to the end of the file.
    The format argument can have any of the following settings:
         TristateUseDefault|-2|Opens the file using the system default.
         TristateTrue|-1|Opens the file as Unicode.
         TristateFalse|0|Opens the file as ASCII.
*/

select @strerrormessage=''opening the file system object''
select @olecmd=''scripting.filesystemobject''
execute @hr = sp_oacreate  @olecmd, @objfilesystem out
if @hr!=0 goto err_ole

if @append=0
    begin
    if @dbg=1 exec sp__printf ''creating file "%s" unicode(%d)'',@file,@unicode
    select @olecmd=''createtextfile''
    execute @hr = sp_oamethod   @objfilesystem   , @olecmd, @objtextstream out, @file,2,@unicode
    if @hr!=0 goto err_ole
    end -- crete
if @append=1
    begin
    if @dbg=1 exec sp__printf ''opening file "%s" unicode(%d)'',@file,@unicode
    select @olecmd=''opentextfile''
    execute @hr = sp_oamethod   @objfilesystem   , @olecmd, @objtextstream out, @file,8,@unicode,-1
    if @hr!=0 goto err_ole
    end -- oepn for append

while 1=1 begin
    if not @table is null begin
        fetch next from cs into @text
        if @@fetch_status!=0 break
    end
    /* -- old version:
    set @i=1
    set @n=dbo.fn__str_count(@text,@crlf)
    while (@i<=@n) begin
        set @row=dbo.fn__str_at(@text,@crlf,@i)
        set @cmd=''echo ''+@row+'' 1>>"''+@file+''"''
        if @dbg=1 print @cmd
        exec master.dbo.xp_cmdshell @cmd,no_output
        set @i=@i+1
    end -- while
    */
    if @addcrlf=1 set @text=@text+@crlf
    select @olecmd=''write''
    execute @hr = sp_oamethod  @objtextstream, @olecmd, null, @text
    if @hr!=0 goto err_ole
    if @table is null break
end -- while write table
select @olecmd=''close''
execute @hr = sp_oamethod  @objtextstream, @olecmd
if @hr!=0 goto err_ole

if not @table is null begin
    close cs
    deallocate cs
end

execute sp_oadestroy @objtextstream
execute sp_oadestroy @objfilesystem
goto ret

-- =================================================================== errors ==

err_file:   exec @ret=sp__err ''file not specified'',@proc goto ret
err_db:     exec @ret=sp__err ''%s must specified after each from'',@proc,@p1=''%db%'' goto ret
err_tbl:    exec @ret=sp__err ''accepted table are #out and #src'',@proc goto ret
err_bcp:    exec @ret=sp__err ''error during generation of xls (%s)'',@proc,@p1=@row goto ret
err_ole:    if @olecmd=''scripting.filesystemobject''
                select @objerrorobject=@objfilesystem
            else
                begin
                select @objerrorobject=@objtextstream
                if @objerrorobject=0
                    select @objerrorobject=@objfilesystem
                end
            execute sp_oageterrorinfo  @objerrorobject,
                @source output,@description output,
                @helpfile output,@helpid output
            exec @ret=sp__err ''file:%s; cmd:%s; src:%s; desc:%s'',
                              @proc,@p1=@file,@p2=@olecmd,@p3=@source,@p4=@description
            execute sp_oadestroy @objtextstream
            execute sp_oadestroy @objfilesystem
            goto ret

-- ===================================================================== help ==

help:
exec sp__usage @proc,''
Scope
    write or append to a text file a string or a table

Parameters
    @file       name of destination file
    @table        optional table name;
                can be only one of this tables:
                #src,#out,#ftpsrc,#htm,#html
    @text       optional line of text to write
    @addcrlf    0 by default, if 1 add a crlf to each line
    @append     0 by default, append to existing file instead of create
    @unicode    0 by default, 1 to write a unicode file instead of ANSI/ASCII
    @uid        not used
    @pwd        not used
''

ret:
return @ret
end -- sp__file_write'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_write:

-- ========================================================= sp__file_write_blob
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_write_blob',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131017
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_write_blob') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_write_blob') with nowait
        goto skip_sp__file_write_blob
        end
    if @ver>131017
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_write_blob') with nowait
        goto skip_sp__file_write_blob
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_write_blob') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_write_blob'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_write_blob]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    c:originally from www.sql.ru (mythical boys)
    v:131017\s.zaglio: about help and tests
    v:130803\s.zaglio: review
    v:100104\s.zaglio: save blob to a binary file
    t:sp__file_write_blob_test 100000000
    t:sp__file_write_blob_test @opt=small
    t:sp__file_write_blob_test @opt=big
    t:sp__file_write_blob_test @opt=huge
*/
CREATE proc [dbo].[sp__file_write_blob]
    @sqlfield nvarchar(4000) = null,
    @file sysname = null,
    @uid sysname = null,
    @pwd sysname = null,
    @blob varbinary(max) = null,
    @dbg bit=0
as
begin
set nocount on
declare
    @proc sysname,@ret int
select
    @proc=object_name(@@procid),@ret=0

declare
    @sql nvarchar(4000),@tmp nvarchar(512),
    @hr int,@obj int,@n int,@buffer int,
    @i int,@chunk varbinary(max)            -- split too big blob

if (nullif(@sqlfield,'''') is null and @blob is null) or @file is null goto help
if @file like ''%..%'' goto err_wpro

exec sp__get_temp_dir @tmp out
select @file=replace(@file,''%temp%'',@tmp)
if @dbg=1 exec sp__printf ''f:%s'',@file

if @sqlfield!=''''
    begin
    if left(@sqlfield,7)=''select ''
        begin
        select @sql=''select @blob=(''+@sqlfield+'')''
        exec sp_executesql @sql,N''@blob varbinary(max) out'',@blob=@blob out
        end
    else
        goto err_fld
    end

-- types: 1=adtypebinary
-- tsave: 2=adsavecreateoverwrite
select @obj=0,@buffer=64*1024--*1024
exec @hr=sp_oacreate ''adodb.stream'', @obj output; if @hr!=0 goto err
exec @hr=sp_oasetproperty @obj, ''type'', 1; if @hr!=0 goto err
exec @hr=sp_oamethod @obj, ''open''; if @hr!=0 goto err
select @n=datalength(@blob),@i=1
while (@i<@n)
    begin
    select @chunk=substring(@blob,@i,@buffer)
    exec @hr=sp_oamethod @obj, ''write'', null, @chunk; if @hr!=0 goto err
    exec @hr=sp_oamethod @obj, ''flush''; if @hr!=0 goto err
    select @i=@i+@buffer
    end
exec @hr=sp_oamethod @obj, ''savetofile'',null,@file,2; if @hr!=0 goto err
exec @hr=sp_oamethod @obj, ''close''; if @hr!=0 goto err
exec @hr=sp_oadestroy @obj;
select @obj=0
goto ret


-- =================================================================== errors ==

err:
declare @source nvarchar(255)
declare @description nvarchar(255)

exec @hr = sp_oageterrorinfo @obj, @source out, @description out
exec @ret=sp__err ''%s;%s'',@proc,@p1=@source,@p2=@description

if @obj!=0 exec sp_oadestroy @obj
goto ret

err_wpro:
exec @ret=sp__err ''worked protection against hackers :-)'',@proc
goto ret

err_fld:
exec @ret=sp__err ''@sqlfield must be a select'',@proc
goto ret

-- ===================================================================== help ==

help:
exec sp__usage @proc,''
Scope
    save a blob to a file

See also
    * sp__file_read_blob

Parameters
    @sqlfield   providede for back compatibility,
                is the select the retrieve the blob
    @file       destination path (support %temp%)
    @uid        not used, provided for old compatibility
    @pwd        not used, provided for old compatibility
    @blob       direct data to save

''
select @ret=-1
goto ret

-- ===================================================================== exit ==
ret:
return @ret
end -- [sp__file_write_blob]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_write_blob:

-- ==================================================== sp__file_write_blob_test
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_write_blob_test',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=131017
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_write_blob_test') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_write_blob_test') with nowait
        goto skip_sp__file_write_blob_test
        end
    if @ver>131017
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_write_blob_test') with nowait
        goto skip_sp__file_write_blob_test
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_write_blob_test') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_write_blob_test'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_write_blob_test]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:131017\s.zaglio: test the sp__file_write_blob
*/
CREATE proc sp__file_write_blob_test
    @size int = null,
    @opt sysname = null,
    @dbg int=0
as
begin try
-- set nocount on added to prevent extra result sets from
-- interferring with select statements.
-- and resolve a wrong error when called remotelly
-- @@nestlevel is >1 if called by other sp (not correct if called by remote sp)

set nocount on

declare
    @proc sysname, @err int, @ret int,  -- @ret: 0=OK -1=HELP, any=error id
    @err_msg nvarchar(2000)             -- used before raise

-- ======================================================== params set/adjust ==
select
    @proc=object_name(@@procid),
    @err=0,
    @ret=0,
    @dbg=isnull(@dbg,0),                -- is the verbosity level
    @opt=nullif(@opt,''''),
    @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end
    -- @param=nullif(@param,''''),

-- ============================================================== declaration ==
declare
    -- generic common
    @huge bit,@small bit,@big bit,@d datetime

-- =========================================================== initialization ==
select
    -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt),
    @huge=charindex(''|huge|'',@opt),
    @small=charindex(''|small|'',@opt),@big=charindex(''|big|'',@opt)

-- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1

-- ======================================================== second params chk ==
if cast(@huge as int)+@small+@big>1 raiserror(''please give only one option'',16,1)
if @size is null and cast(@huge as int)+@small+@big=0 goto help

-- =============================================================== #tbls init ==

-- ===================================================================== body ==

declare @v varbinary(max)

if @small=1 select @size=3998
if @big=1 select @size=11998
if @huge=1 select @size=200000000

exec sp__elapsed @d out,''Begin test''
select @v=cast(
            ''a''+replicate(cast(''b'' as varchar(max)),@size)+
            ''z'' as varbinary(max))
select @size=len(@v)
exec sp__elapsed @d out,''after generating blob a...z of %d bytes'',@v1=@size

exec sp__file_write_blob
        @file=''%temp%\sp__file_write_blob_test.txt'',
        @blob=@v

exec sp__elapsed @d out,''after write''

-- ================================================================== dispose ==
dispose:
-- drop temp tables, flush data, etc.

goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,''
Scope
    test sp__file_write_blob, writing a huge text file (2gb)
    to %temp%\sp__file_write_blob_test.txt

Parameters
    [param]     [desc]
    @size       dynamic number of bytes to test
    @opt        options
                small   test a 4000 bytes blob
                big     test a 12000 bytes blob
                huge    test a 2.000.000.002 bytes blob
    @dbg        1=last most importanti info/show code without execute it
                2=more up level details
                3=more up ...

Examples
    [example]
''

select @ret=-1

-- ===================================================================== exit ==
ret:
return @ret
end try

-- =================================================================== errors ==
begin catch
-- if @@trancount > 0 rollback -- for nested trans see style "procwnt"

exec @ret=sp__err @cod=@proc,@opt=''ex''
return @ret
end catch   -- proc sp__file_write_blob_test'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_write_blob_test:

-- ======================================================= sp__file_write_stream
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__file_write_stream',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=121118
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__file_write_stream') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__file_write_stream') with nowait
        goto skip_sp__file_write_stream
        end
    if @ver>121118
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__file_write_stream') with nowait
        goto skip_sp__file_write_stream
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__file_write_stream') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__file_write_stream'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__file_write_stream]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:121118\s.zaglio: added out option and info to skip BOM
    v:121026\s.zaglio: added @txt
    v:120723\s.zaglio: added html opt
    v:110621\s.zaglio: write a text file with different format
    t:
        declare @d datetime
        create table #src(lno int identity,line nvarchar(4000))
        insert #src select name+'' ''+name+'' ''+name+'' ''+name from syscolumns
        exec sp__elapsed @d out,''Init''
        exec sp__file_write_stream ''%temp%\stream_test1.txt''
        exec sp__elapsed @d out,''after stream in utf8''
        exec sp__file_write ''%temp%\stream_test2.txt'',@table=''#src'',@addcrlf=1,@unicode=1
        exec sp__elapsed @d out,''after fileobject in unicode''
        exec master..xp_cmdshell ''del /q /f %temp%\stream_test1.txt'',no_output
        exec master..xp_cmdshell ''del /q /f %temp%\stream_test2.txt'',no_output
        drop table #src
*/
CREATE proc [dbo].[sp__file_write_stream]
    @path nvarchar(1024)=null,
    @fmt sysname        =null,
    @sep nvarchar(2)    =null,
    @txt nvarchar(max)  =null,
    @opt sysname        =null,
    @dbg int            =0
as
begin
set nocount on
declare @proc sysname,@ret int
select
    @proc=object_name(@@procid),@ret=0,
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''||'')

if @fmt is null select @fmt=''utf-8''
if @txt is null and @sep is null select @sep=crlf from fn__sym()

-- ============================================================= declarations ==
declare
    @tmp nvarchar(512),@cmd sysname,@hr int,@obj int,@line nvarchar(4000),
    @html bit,@src bit,@out bit,@ll int

-- ===================================================================== init ==

select
    @src=isnull(object_id(''tempdb..#src''),0),
    @html=charindex(''|html|'',@opt),
    @out=charindex(''|out|'',@opt)

if @out=1 and object_id(''tempdb..#out'') is null goto err_out
if @html=1 and object_id(''tempdb..#html'') is null goto err_htm
if not @txt is null and not @sep is null goto err_txs

if @out=1 or @html=1 select @src=0      -- exclude #src of parent process

if @path is null and @src=0 and @html=0 and @out=0 and @txt is null
    goto help

if @path like ''%[%]temp[%]%''
    begin
    exec sp__get_temp_dir @tmp out
    select @path=replace(@path,''%temp%'',@tmp)
    if @dbg=1 exec sp__printf ''path:%s'',@path
    end

if @path like ''%..%'' goto err_wpro

select @cmd=''ADODB.Stream''
exec @hr = sp_oacreate @cmd, @obj out
if @hr!=0 goto err_ole
select @cmd=''Type''
exec @hr = sp_oasetproperty  @obj ,@cmd,2 -- text
if @hr!=0 goto err_ole
select @cmd=''charset''
exec @hr = sp_oasetproperty  @obj ,@cmd,@fmt
if @hr!=0 goto err_ole
select @cmd=''Open''
exec @hr = sp_oamethod  @obj , @cmd, null
if @hr!=0 goto err_ole
-- UTFStream.Position = 3 ''skip BOM
select @cmd=''WriteText''
if not @txt is null
    exec @hr = sp_oamethod  @obj , @cmd, null, @txt, 0
else
    begin
    if @html=1
        begin
        select @ll=max(lno) from #html
        declare cs cursor local for
            select isnull(line,'''')+case lno when @ll then '''' else @sep end
            from #html
            order by lno
        end
    if @src=1
        begin
        select @ll=max(lno) from #src
        declare cs cursor local for
            select isnull(line,'''')+case lno when @ll then '''' else @sep end
            from #src
            order by lno
        end
    if @out=1
        begin
        select @ll=max(lno) from #out
        declare cs cursor local for
            select isnull(line,'''')+case lno when @ll then '''' else @sep end
            from #out
            order by lno
        end

    open cs
    while 1=1
        begin
        fetch next from cs into @line
        if @@fetch_status!=0 break
        -- default line separator keep data attached
        exec @hr = sp_oamethod  @obj , @cmd, null, @line, 0
        -- todo: remove bom
        -- objStream.Position = objStream.Size ''write at the beginning of the stream .ie. overwrite all
        if @hr!=0 goto err_ole
        end -- while of cursor
    close cs
    deallocate cs
    end

/*
UTFStream.Position = 3 ''skip BOM

Dim BinaryStream As Object
Set BinaryStream = CreateObject("adodb.stream")
BinaryStream.Type = adTypeBinary
BinaryStream.Mode = adModeReadWrite
BinaryStream.Open

''Strips BOM (first 3 bytes)
UTFStream.CopyTo BinaryStream

''UTFStream.SaveToFile "d:\adodb-stream1.txt", adSaveCreateOverWrite
UTFStream.Flush
UTFStream.Close

BinaryStream.SaveToFile "d:\adodb-stream2.txt", adSaveCreateOverWrite
BinaryStream.Flush
BinaryStream.Close
*/
select @cmd=''SaveToFile''
exec @hr = sp_oamethod  @obj , @cmd, null, @path, 2 -- adSaveCreateOverwrite
if @hr!=0 goto err_ole

goto ret

-- =================================================================== errors ==
err_wpro:
exec @ret=sp__err ''worked protection against hackers :-) '',@proc
goto ret

err_txs:
exec @ret=sp__err ''@sep is not compatible with @txt'',@proc
goto ret

err_ole:
declare @source nvarchar(255)
declare @description nvarchar(255)
exec @hr = sp_oageterrorinfo @obj, @source out, @description out
exec @hr = sp_oadestroy @obj
select @obj=null
exec @ret=sp__err ''ole error (%s;%s;%s)'',@proc,@p1=@cmd,@p2=@source,@p3=@description
goto ret

err_htm:
exec @ret=sp__err ''#html not found'',@proc
goto ret

err_out:
exec @ret=sp__err ''#out not found'',@proc
goto ret

-- ===================================================================== help ==
help:
exec sp__usage @proc,N''
Scope
    write a text file, using adodb.stream to allow charset types

Parameters
    #src    source text lines (lno int identity,line nvarchar(4000))
    #out    alternative source test lines if "out" option is specified
    #html   alternative source text lines
    @fmt    is the format of source file (default is "utf-8")
            See list below
    @sep    line separator (default is CRLF)
    @txt    a single full text varable
    @opt    options
            html    use #html instead of #src as source
            out     use #out instead of #src as source

Example
    create table #src(lno int identity,line nvarchar(4000))
    insert #src select ''''line one''''
    insert #src select N''''line with unicode Джон''''
    insert #src select ''''line tree''''
    exec sp__file_write_stream ''''%temp%\stream_test.txt'''',@dbg=1
    exec master..xp_cmdshell ''''type %temp%\stream_test.txt''''
    exec master..xp_cmdshell ''''del /q /f %temp%\stream_test.txt'''',no_output
    drop table #src

    declare @txt as nvarchar(max)
    declare @i int select @txt=N''''line with unicode Джон''''+char(13)+char(10),@i=16
    while @i>0 select @txt=@txt+@txt,@i=@i-1
    print datalength(@txt)
    select @txt=''''begin''''+char(13)+@txt+''''end''''
    exec sp__file_write_stream ''''%temp%\stream_test.txt'''',@txt=@txt
    exec xp_cmdshell ''''dir %temp%\stream_test.txt''''
    -- check on server and then delete file

-- List of accepted formats --
''
create table #fmts(line sysname)
insert #fmts
    exec master..xp_regenumkeys ''HKEY_CLASSES_ROOT'',''MIME\Database\Charset''
exec sp__select_astext ''select line from #fmts order by 1''
drop table #fmts

select @ret=-1
goto ret

ret:
if @obj!=0 exec @hr = sp_oadestroy @obj
set nocount off
return @ret
end -- [sp__file_write_stream]'

end try
begin catch
exec #script_catch 'utility',@repeat
if not error_number() in (208,207)
    begin
    select @emsg=error_message(),@esev=error_severity(),@ests=error_state()
    raiserror(@emsg,@esev,@ests)
    end
end catch
skip_sp__file_write_stream:

-- ==================================================================== sp__find
select @ver=null,@aut=null
exec sp_executesql N'
    select
        @ver=cast(val1 as decimal(10,4)),
        @aut=val2
    from dbo.fn__script_info(@obj,@typ,0)
    ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out',
    @obj='sp__find',@typ='rv',@ver=@ver out,@aut=@aut out
if not @ver is null
    begin
    if @ver=140122
        begin
        if @aut!='s.zaglio'
            raiserror('local "%s.%s" with same version but different author',
                      16,1,@db,'sp__find') with nowait
        raiserror('skipped "%s.%s" because local is the same',
                  10,1,@db,'sp__find') with nowait
        goto skip_sp__find
        end
    if @ver>140122
        begin
        raiserror('skipped "%s.%s" because local is more recent',
                  10,1,@db,'sp__find') with nowait
        goto skip_sp__find
        end
    end

raiserror('re-creating "%s.%s"',10,1,@db,'sp__find') with nowait

if exists(
    select top 1 null from sys.objects
    where name='sp__find'

    and schema_id=schema_id('dbo')
    )
    drop proc [dbo].[sp__find]

begin try
exec dbo.sp_executesql @statement = N'/*  leave this
    l:see LICENSE file
    g:utility
    v:140122\s.zaglio: commented search into tags
    r:130925\s.zaglio: used try-catch to ensure search continuity
    v:130612\s.zaglio: adapted to new fn__sym
    v:121025\s.zaglio: added option distinct
    v:120827\s.zaglio: added autoscale to %word% if nothing is found
    v:120726.1600\s.zaglio: help,svn context and added func/sub name in list
    v:120614.1715\s.zaglio: exclude "-" from symbols and managed [word]
    v:120601\s.zaglio: a bug in search of exact col
    v:120229\s.zaglio: extended correctly search to obj & cols name
    v:120208\s.zaglio: inverted logic and option NOSVN to SVN
    v:120207\s.zaglio: again a small bug near existance of db utility
    v:120203\s.zaglio: added #sp__find_out and removed a small bug
    v:120127\s.zaglio: done
    r:120125\s.zaglio: working
    r:120123\s.zaglio: adding svn management
    v:120116\s.zaglio: added @range and restyled
    v:111216\s.zaglio: added "s" as separator symbol
    v:111116\s.zaglio: about help
    v:111031\s.zaglio: removed @dbs, added opt "script" and improved generic search
    v:111011\s.zaglio: added () as symbols
    v:111003\s.zaglio: added tags search and correct a bug near @m2=@m3
    v:110920\s.zaglio: added tab symbol
    v:110914\s.zaglio: added symbols : and \, @obj and @xtype
    v:110713\s.zaglio: a bug near code search
    v:110712\s.zaglio: added sep. symbols .#10#13#32
    v:110623\s.zaglio: added table name near columns
    v:110331\s.zaglio: optimized
    v:110530\s.zaglio: remake
    t:sp__find ''sp__find'',@dbg=1
    t:sp__find ''sp__job_status''
    t:sp__find ''PDA_DISABLE_MULTI_LABELLING'',@opt=''txt''
    t:sp__find ''[utility]'',@dbg=2
    t:sp__find ''%[utility]'',@dbg=2
*/
CREATE PROC sp__find
    @what  sysname = null,
    @obj   sysname = null,
    @xtype sysname = null,
    @range int     = null,
    @opt   sysname = null,
    @dbg   int=0
as
begin
-- set nocount on added to prevent extra result sets from
-- interfering with select statements.
set nocount on
-- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg''
declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id
select  @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0)
select
    @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''),
    @obj=dbo.fn__str_quote(@obj,''%'')
-- ========================================================= param formal chk ==

-- ============================================================== declaration ==
declare
    @m1 sysname,@m2 sysname,@m3 sysname,@m4 sysname,
    @left sysname,@right sysname,@db sysname,@sym sysname,
    @sql nvarchar(4000),@params nvarchar(4000),
    @dbs sysname,@tags bit,@rows int,@typ sysname,
    @cmd nvarchar(1024),@url nvarchar(1024),@tmp nvarchar(4000),
    @file sysname,@d datetime,@n bigint,
    @id int,@rid int,@rev sysname,
    @crlf nvarchar(4),@cr nvarchar(2),@lf nvarchar(2),@tab nvarchar(2),
    @target nvarchar(1024),@path nvarchar(1024),
    @svn_export nvarchar(1024),@svn_dir nvarchar(1024),
    @svn_list nvarchar(1024), @svn_del_target nvarchar(1024),
    @svn_diff nvarchar(1024),@i int,@emsg nvarchar(2048),
    @svn bit                -- nosvn option


declare @stdout table (lno int identity primary key, line nvarchar(4000))
declare @files table (id int null,rev int,name nvarchar(1024))
declare @paths table (name nvarchar(1024))

create table #sql(id int identity,typ sysname,sql nvarchar(4000))
create table #src(lno int identity,line nvarchar(4000))
create table #dbs(db sysname)
create table #sysobjects(id int,[name] sysname,xtype nvarchar(4))

if object_id(''tempdb..#tmp_found'') is null
    create table #tmp_found(
        db sysname null,
        id sql_variant null, number int null, colid int null,
        p1 int null,p2 int null,p3 int null,
        obj sysname null,
        xtype sysname null,
        [txt1_or_obj] sysname null,
        [txt2_or_type] sysname null,
        txt3 sysname null
        )

-- =========================================================== initialization ==

select
    @cr=cr,@lf=lf,@tab=tab,@crlf=crlf,
    @sym=bounds,
    @cmd=''svn'',
    @target=''%temp%\''+replace(cast(newid() as sysname),''-'',''_'')+''.txt''
from fn__sym()

if charindex(''|dbs|'',@opt)>0
    begin
    select @dbs=''%''
    insert into #dbs(db)
    select [name]
    from master..sysdatabases
    where [name] like @dbs
    end
else
    insert #dbs(db) select db_name()

-- NB: escape not exists for patindex so I replace ] with ¬
select
    @what=  case
            when left(@what,1)=''['' and right(@what,1)='']''
            then replace(replace(@what,'']'',''¬''),''['',''[[]'')
            else @what
            end,
            -- dbo.fn__str_unquote(@what,''[]''),
    @tags=  charindex(''|tags|'',@opt),
    @range= case
            when @range is null
            then
                case
                when len(@what)+1>20
                then len(@what)+1
                else 20
                end
            else @range
            end,
    @left=  case
            when left(@what,1) like ''[0-9a-Z]''
              or left(@what,1) = ''[''
            then ''%[ [''+@sym+'']''
            else ''%''
            end,
    @right= case
            when right(@what,1) like ''[0-9a-Z]''
              or right(@what,1) = ''[''
            then ''[ [''+@sym+'']%''
            else ''%''
            end

select
    @m1=@left+@what+@right, -- single word
    @m2=@what+@right,
    @m3=@left+@what,
    @params=''@what sysname,@m1 sysname,@m2 sysname,@m3 sysname,''
           +''@range int,@db sysname,@xtype sysname,@obj sysname,''
           +''@err int out,@rows int out,@dbg int''

-- ======================================================== second params chk ==
if @what is null goto help

-- ===================================================================== body ==

if @dbg>0 exec sp__printf ''declare
    @what sysname,@xtype sysname,@m1 sysname,@m2 sysname,@m3 sysname,
    @db sysname,@obj sysname

select
    @what=  ''''%s'''',
    @m1=    ''''%s'''',
    @m2=    ''''%s'''',
    @m3=    ''''%s''''
    '',@what,@m1,@m2,@m3

-- ##########################
-- ##
-- ## svn
-- ##
-- ########################################################

if charindex(''|svn|'',@opt)>0
or left(@what,4)=''svn:''
    select @svn=1
else
    select @svn=0

-- svn file caching uses only one common table on utility db
if @svn=1
and exists(
    select null
    from master..sysdatabases
    where name=''utility''
    )
    begin

    if object_id(''utility..fnd'') is null
        begin
        -- drop table fnd
        exec(''
        create table utility..fnd(
            tid tinyint not null,   -- filename or text line
            id int identity constraint pk_fnd primary key,
            rid int not null,
            pid int not null,
            idx int not null,       -- file row number
            [key] int,              -- revision
            val nvarchar(4000)      -- name
            )
        create index ix_fnd on fnd(tid,rid,id)
        '')
        end -- fnd creation

    if db_name()!=''utility'' and object_id(''fnd'') is null
        exec(''create view fnd as select * from utility..fnd'')

    end -- creation of table or alias
else
    goto search

if object_id(''fnd'') is null
    begin
    select @svn=0
    goto search
    end

-- list or load new path, or refresh path
if left(@what,4)=''svn:''
    insert @paths select @what
else
    -- refresh previous cached paths
    insert @paths
    select val from fnd,tids where fnd.tid=tids.url

-- for each new path or previous path
declare cs cursor local for
    select name
    from @paths
open cs
while 1=1
    begin
    fetch next from cs into @path
    if @@fetch_status!=0 break

    select
        @url=protocol+''://''+host+path,
        @file=page,
        @svn_export=@cmd+'' export "''+@url+''%file%" ''+@target+'' -r HEAD'',
        @svn_dir=@cmd+'' ls -r HEAD ''+@url,
        @svn_list=@cmd+'' ls -r HEAD -R -v ''+@url, -- username X --password Y
        @svn_diff=@cmd+'' diff -r ''+@rev+'':HEAD --summarize ''+@url,
        @svn_del_target=''del ''+@target
    from fn__parseurl(@path,default)

    if @dbg=1
        begin
        exec sp__printf ''svn_dir:%s'',@svn_dir
        exec sp__printf ''target:%s'',@target
        end -- dbg

    -- sp__find ''svn://svr/SOURCES'',@dbg=1
    if isnull(@file,'''')=''''
        begin
        exec master..xp_cmdshell @svn_dir
        continue
        end

    -- list and import files
    -- select * from fnd -- drop table fnd
    -- sp__find ''svn://svr/SOURCES/prg/trunk/*.vb'',@dbg=1

    select @rid=null,@d=null

    select
        @rid=id,
        @d=cast(cast(nullif([key],0) as binary(4)) as smalldatetime) /* ...
           ... contain last ins/update time */
    from fnd,tids
    where fnd.tid=tids.url
    and val=@path

    if @rid is null
        begin
        if charindex(''|clean|'',@opt)>0
            begin
            exec sp__printf ''-- nothing to clean''
            continue
            end -- clean

        -- list all files
        select @d=getdate()
                -- store path and time to not overlap multiple imports
        insert fnd(
            tid,rid,pid,idx,
            [key],val
            )
        select top 1
            tids.url,0 as rid,0 as pid,0 as idx,
            cast(cast(@d as smalldatetime) as binary(4)),       -- lock import
            @what
        from tids
        select @rid=@@identity

        exec sp__printf ''-- populating new path on id %d'',@rid

        insert @stdout exec master..xp_cmdshell @svn_list

        select top 1 @tmp=line
        from @stdout
        where line like ''svn:%''
        order by lno

        -- if there is an error, unlock (deleting) the id
        if @@rowcount>0
            begin
            delete from fnd where id=@rid
            goto err_svn
            end

        select @n=count(*) from @stdout where line like replace(@file,''*'',''%'')
        exec sp__elapsed @d out,''-- after get list to download %d files'',@v1=@n
        if @n=0 goto ret

        -- extract columns and filtered files
        insert @files(rev,name)
        select left(line,7) rev,substring(line,44,512) [file]
        from @stdout
        where not line is null
        and line like replace(@file,''*'',''%'')

        end -- populate files
    else
        begin
        -- sp__find ''svn://svr/SOURCES/prg/trunk/*.vb'',@dbg=1

        if not @d is null               -- if locked
            begin

            if left(@what,4)!=''svn:''
                begin
                -- skip msg if are searching
                select @d=null -- do not show svn times
                continue
                end

            if charindex(''|unlock|'',@opt)>0
                begin
                exec sp__printf ''-- unlocked''
                update fnd set [key]=0 where id=@rid
                select @d=null  -- this skipp next if and not show svn times
                end

            if datediff(hh,@d,getdate())>1
                begin
                exec sp__elapsed @d,''-- automatic unlock of importing "%s"(id:%d) from'',
                                 @v1=@path,@v2=@rid
                update fnd set [key]=0 where id=@rid
                end
            else
                begin
                exec sp__elapsed @d,''-- already importing "%s"(id:%d) from'',
                                 @v1=@path,@v2=@rid
                select @d=null -- do not show svn times
                continue
                end
            end

        select @d=getdate()
        if charindex(''|clean|'',@opt)>0
            begin
            delete from fnd where pid=@rid
            select @n=@@rowcount
            exec sp__elapsed @d,''-- cleaned %d rows in'',@v1=@n
            select @d=null -- do not show svn times
            continue
            end -- clean

        update fnd set
            [key]=cast(cast(@d as smalldatetime) as binary(4)) -- lock update
        where id=@rid

        -- search for last
        select @rev=max([key])
        from fnd,tids
        where fnd.tid=tids.obj and rid=@rid

        if left(@what,4)=''svn:''
            exec sp__printf ''-- get updated files from revision %s for path %s'',
                            @rev,@path

        insert @stdout exec master..xp_cmdshell @svn_diff

        if exists(
            select top 1 null
            from @stdout
            where line like ''svn:%''
            order by lno
            )
            begin
            continue -- revision not found
            update fnd set [key]=0 where id=@rid
            end

        delete from @stdout

        -- list all files
        insert @stdout exec master..xp_cmdshell @svn_list

        -- extract columns
        insert @files(rev,name)
        select left(line,7) rev,substring(line,44,512) [file]
        from @stdout
        where not line is null
        and line like replace(@file,''*'',''%'')

        -- unlist files of same revision
        delete f
        from @files f
        join fnd on f.name=fnd.val
        cross join tids
        where fnd.tid=tids.obj
        and rid=@rid
        and f.rev=fnd.[key]

        -- update ref id of existing files so can be replaced
        update f set id=fnd.id
        from @files f
        join fnd on f.name=fnd.val
        cross join tids
        where fnd.tid=tids.obj
        and rid=@rid

        end -- update path

    end -- while of cursor
close cs
deallocate cs

-- download files/refresh cache
if exists(select null from @files)
    begin
    select @i=0
    declare cs cursor local for
        select id,rev,name
        from @files
    open cs
    while 1=1
        begin
        fetch next from cs into @id,@rev,@file
        if @@fetch_status!=0 break

        -- get file from svn into a generic container
        select @tmp=replace(@svn_export,''%file%'',@file)
        if @dbg=1 exec sp__printf ''%s'',@tmp

        -- export file from svn
        delete from @stdout
        insert @stdout exec master..xp_cmdshell @tmp

        if not exists(
            select top 1 null
            from @stdout
            where line like ''A %.txt''
            order by lno
            )
            goto err_svn

        -- import generic container
        truncate table #src
        exec @ret=sp__file_read_stream @target,@out=''#src''

        if @ret=0
            begin
            if not @id is null
                -- replace old version
                delete from fnd where rid=@id

            select @id=null

            insert fnd(tid,rid,pid,idx,[key],val)
            select tids.obj,@rid,@rid,0,@rev,@file
            from tids

            select @id=@@identity

            insert fnd(tid,rid,pid,idx,val)
            select tids.code,@id,@rid,src.lno,ltrim(rtrim(src.line))
            from #src src,tids
            where ltrim(rtrim(isnull(line,'''')))!=''''
            order by lno
            select @n=@@rowcount
            exec sp__printf ''-- downloaded %d lines from file %d:%s(r:%d)'',
                            @n,@i,@file,@rev
            select @i=@i+1
            end -- load ok

        end -- while of cursor
    close cs
    deallocate cs

    -- unlock import
    update fnd set [key]=0 where id=@rid

    exec master..xp_cmdshell @svn_del_target,no_output

    end -- download files

if not @d is null exec sp__elapsed @d,''-- svn elaboration in''

if left(@what,4)=''svn:''  goto ret

-- ##########################
-- ##
-- ## search
-- ##
-- ########################################################

search:

-- ##########################
-- ##
-- ## tags
-- ##
-- ########################################################
/*
insert #sql select ''tags'',''
use [%db%]
insert #tmp_found(
    db,id,obj,xtype,[txt1_or_obj],[txt2_or_type],txt3
    )
select
    @db db,
    obj_id,
    obj,
    tag+'''':'''',
    convert(sysname,val1) [txt1_or_obj],
    convert(sysname,val2) [txt2_or_type],
    convert(sysname,val3) txt3
from dbo.fn__script_info(default,''''gkvrt'''',default) tags
join sysobjects o on o.id=tags.obj_id
where 1=1
and not (val1 is null and val2 is null and val3 is null)
and (@xtype is null or o.xtype=@xtype)
and (  isnull(convert(sysname,val1),'''''''') like @m1
    or isnull(convert(sysname,val1),'''''''') like @m2
    or isnull(convert(sysname,val1),'''''''') like @m3
    or isnull(convert(sysname,val1),'''''''') = @what

    or isnull(convert(sysname,val2),'''''''') like @m1
    or isnull(convert(sysname,val2),'''''''') like @m2
    or isnull(convert(sysname,val2),'''''''') like @m3
    or isnull(convert(sysname,val2),'''''''') = @what

    or isnull(convert(sysname,val3),'''''''') like @m1
    or isnull(convert(sysname,val3),'''''''') like @m2
    or isnull(convert(sysname,val3),'''''''') like @m3
    or isnull(convert(sysname,val3),'''''''') = @what
    )
select @rows=@@rowcount
''
*/
-- ##########################
-- ##
-- ## code
-- ##
-- ########################################################
insert #sql select ''code'',''
use [%db%]
-- first fast pass filter
insert into #sysobjects(id,name,xtype)
select id,name,xtype
from sysobjects o with (nolock)
where 1=1
and (@xtype is null or ltrim(rtrim(o.xtype)) like @xtype)
and (@obj is null or o.name like @obj)
select @rows=@@rowcount
if @dbg=2 exec sp__printf ''''-- found %d sysobjs'''',@rows

-- second fast pass filter
declare @owhat sysname
select @owhat=replace(@what,''''¬'''','''']'''')
select c.id,number,colid,[text]
into #syscomments
from syscomments c with (nolock)
join #sysobjects o on o.id=c.id
where [text] like ''''%''''+@owhat+''''%''''
select @rows=@@rowcount
if @dbg=2 exec sp__printf ''''-- found %d syscomments'''',@rows

-- search into source
insert #tmp_found(db,id,number,colid,p1,p2,p3)
select
    @db,id,number,colid,
    patindex(@m1,replace([text],'''']'''',''''¬'''')) p1,
    patindex(@m2,replace([text],'''']'''',''''¬'''')) p2,
    patindex(@m3,replace([text],'''']'''',''''¬'''')) p3
from #syscomments
where patindex(@m1,replace([text],'''']'''',''''¬''''))>0
or patindex(@m2,replace([text],'''']'''',''''¬''''))>0
or patindex(@m3,replace([text],'''']'''',''''¬''''))>0

-- if nothing found, autoscale to %word%
if @@rowcount=0
    insert #tmp_found(db,id,number,colid,p1,p2,p3)
    select
        @db,id,number,colid,
        patindex(''''%''''+@owhat+''''%'''',[text]) p1,
        0 p2,
        0 p3
    from syscomments c with (nolock)
    where [text] like ''''%''''+@owhat+''''%''''

update #tmp_found set
    obj=o.name,
    xtype=o.xtype,
    [txt1_or_obj]=
        case when p1>0
        then substring(c.[text],p1-@range,p1+@range-p1+@range)
        else ''''''''
        end,
    [txt2_or_type]=
        case when p2>0
        then substring(c.[text],p2-@range,p2+@range-p2+@range)
        else ''''''''
        end,
    txt3=
        case when p3>0
        then substring(c.[text],p3-@range,p3+@range-p3+@range)
        else ''''''''
        end
from #tmp_found t
join #sysobjects o with (nolock) on t.id=o.id
join #syscomments c with (nolock) on c.id=t.id and c.number=t.number and c.colid=t.colid
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## objects
-- ##
-- ########################################################
insert #sql select ''objs'',''
use [%db%]
-- search into objects
insert #tmp_found(db,id,obj,xtype)
select @db,id,[name],xtype
from #sysobjects o with (nolock)
where patindex(@m1,replace(o.name,'''']'''',''''¬''''))>0
or patindex(@m2,replace(o.name,'''']'''',''''¬''''))>0
or patindex(@m3,replace(o.name,'''']'''',''''¬''''))>0
or o.name=@what
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## columns
-- ##
-- ########################################################
insert #sql select ''cols'',''
use [%db%]
insert #tmp_found(
    db,id,obj,xtype,[txt1_or_obj],[txt2_or_type]
    )
select @db,c.id,c.[name],t.name,o.name,o.xtype
from syscolumns c with (nolock)
join systypes t on c.xusertype=t.xusertype
left join sysobjects o with (nolock) on c.id=o.id
where patindex(@m1,replace(c.name,'''']'''',''''¬''''))>0
or patindex(@m2,replace(c.name,'''']'''',''''¬''''))>0
or patindex(@m3,replace(c.name,'''']'''',''''¬''''))>0
or @what=c.name
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## job steps
-- ##
-- ########################################################
insert #sql select ''jsteps'',''
use [%db%]
insert #tmp_found(
    db,id,colid,obj,xtype,[txt1_or_obj],p1,p2,p3
    )
select
    @db,j.job_id,s.step_id,
    j.name,
    ''''job.step'''',
    left(s.step_name,128),
    patindex(@m1,replace(s.step_name,'''']'''',''''¬'''')),
    patindex(@m2,replace(s.step_name,'''']'''',''''¬'''')),
    patindex(@m3,replace(s.step_name,'''']'''',''''¬''''))
from msdb..sysjobsteps s with (nolock)
join msdb..sysjobs j with (nolock)
on s.job_id=j.job_id
where database_name=@db
and (
       patindex(@m1,replace(s.step_name,'''']'''',''''¬''''))>0
    or patindex(@m2,replace(s.step_name,'''']'''',''''¬''''))>0
    or patindex(@m3,replace(s.step_name,'''']'''',''''¬''''))>0
    )
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## job commands
-- ##
-- ########################################################
insert #sql select ''jcmds'',''
use [%db%]
-- search into jobs command
insert #tmp_found(
    db,id,colid,obj,xtype,[txt1_or_obj],p1,p2,p3
    )
select
    @db as db,j.job_id as id,s.step_id as colid,
    left(j.name+''''.''''+s.step_name,128) as obj,
    ''''job.step.cmd'''' as xtype,
    left(s.command,128) as [txt1_or_obj],
    patindex(@m1,replace(s.command,'''']'''',''''¬'''')) as p1,
    patindex(@m2,replace(s.command,'''']'''',''''¬'''')) as p2,
    patindex(@m3,replace(s.command,'''']'''',''''¬'''')) as p3
from msdb..sysjobsteps s with (nolock)
join msdb..sysjobs j with (nolock)
on s.job_id=j.job_id
where database_name=@db
and (
       patindex(@m1,replace(s.command,'''']'''',''''¬''''))>0
    or patindex(@m2,replace(s.command,'''']'''',''''¬''''))>0
    or patindex(@m3,replace(s.command,'''']'''',''''¬''''))>0
    )

update #tmp_found set
    [txt1_or_obj]=
        case when p1>0
        then substring(s.command,p1-@range,p1+@range-p1+@range)
        else ''''''''
        end,
    [txt2_or_type]=
        case when p2>0
        then substring(s.command,p2-@range,p2+@range-p2+@range)
        else ''''''''
        end,
    txt3=
        case when p3>0
        then substring(s.command,p3-@range,p3+@range-p3+@range)
        else ''''''''
        end
from #tmp_found t
join msdb..sysjobsteps s with (nolock) on t.id=s.job_id and t.colid=s.step_id
where t.xtype=''''job.step.cmd''''
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## jobs name
-- ##
-- ########################################################
insert #sql select ''jobs'',''
insert #tmp_found(id,obj,xtype)
select
    j.job_id,
    j.name,
    ''''job''''
from msdb..sysjobs j with (nolock)
where j.name like @what
select @rows=@@rowcount
''

-- ##########################
-- ##
-- ## svn cache
-- ##
-- ########################################################
insert #sql select ''svn'',''
declare @d datetime select @d=getdate()
-- 1st fast pass filter
select c.rid as id,c.id as colid,[val] as [text],c.idx
into #syscomments
from fnd c with (nolock),tids
where c.tid=tids.code and [val] like ''''%''''+@what+''''%''''
if @dbg=1 exec sp__elapsed @d out,''''-- after 1st pass''''

-- search into source
declare @tobj tinyint
select @tobj=obj from tids
insert #tmp_found(id,colid,p1,p2,p3)
select
    id,colid,
    patindex(@m1,replace([text],'''']'''',''''¬'''')) p1,
    patindex(@m2,replace([text],'''']'''',''''¬'''')) p2,
    patindex(@m3,replace([text],'''']'''',''''¬'''')) p3
from #syscomments c
where patindex(@m1,replace([text],'''']'''',''''¬''''))>0
or patindex(@m2,replace([text],'''']'''',''''¬''''))>0
or patindex(@m3,replace([text],'''']'''',''''¬''''))>0
select @rows=@@rowcount
if @dbg=1 exec sp__elapsed @d out,''''-- after 2nd pass''''

-- extract functions/sub name and line range

if @dbg=1 exec sp__elapsed @d out,''''-- after 3rd pass''''

update #tmp_found set
    db=substring(
        o.val,
        charindex(''''://'''',o.val),
        dbo.fn__charindex(''''/'''',o.val,-1)-charindex(''''://'''',o.val)
        ),
    obj=substring(o.val,dbo.fn__charindex(''''/'''',o.val,-1)+1,128),
    xtype=''''svn'''',
    [txt1_or_obj]=f.obj,
    [txt2_or_type]=
        case f.typ when 1 then ''''sub'''' else ''''function'''' end,
    txt3=
        case
        when p1>0
        then substring(c.[text],p1-@range*2,p1+@range-p1+@range*2)
        when p2>0
        then substring(c.[text],p2-@range*2,p2+@range-p2+@range*2)
        when p3>0
        then substring(c.[text],p3-@range*2,p3+@range-p3+@range*2)
        else ''''''''
        end
from #tmp_found t
join fnd o with (nolock) on o.tid=@tobj and t.id=o.id   -- extract path
join #syscomments c with (nolock) on c.id=t.id and c.colid=t.colid
join #func f on c.idx between f.[from] and f.[to] and c.id=f.rid
if @dbg=1 exec sp__elapsed @d out,''''-- after 3rd pass''''
''

-- ===================================================== parse functions/subs ==
if @svn=1 select * into #func from (
    select
        a.rid,-- f.val as [file],
        1 typ,
        ltrim(substring(a.val,charindex(''sub '',a.val)+4,charindex(''('',a.val)-charindex(''sub '',a.val)-4)) as obj,
        a.idx [from],
        (select top 1 b.idx
         from fnd b
         where a.rid=b.rid and b.idx>a.idx
         and patindex(''end sub%'',ltrim(b.val))>0
         order by b.idx
        ) [to]
    from fnd a
    join fnd f on a.rid=f.id
    where left(ltrim(a.val),1)!=''''''''
    and patindex(''end sub%'',ltrim(a.val))=0
    and (patindex(''sub %'',a.val)>0
         or patindex(''% sub %'',a.val)>0
        )
    and patindex(''delegate %'',a.val)=0
    and patindex(''% delegate %'',a.val)=0
    and charindex(''('',a.val)>charindex(''sub '',a.val)

    union

    select
        a.rid,-- f.val as [file],
        0 typ,
        ltrim(substring(a.val,charindex(''function '',a.val)+9,charindex(''('',a.val)-charindex(''function '',a.val)-9)) as obj,
        a.idx [from],
        (select top 1 b.idx
         from fnd b
         where a.rid=b.rid and b.idx>a.idx
         and patindex(''end function%'',ltrim(b.val))>0
         order by b.idx
        ) [to]
    from fnd a
    join fnd f on a.rid=f.id
    where left(ltrim(a.val),1)!=''''''''
    and patindex(''end function%'',ltrim(a.val))=0
    and (patindex(''function %'',a.val)>0
         or patindex(''% function %'',a.val)>0
        )
    and patindex(''delegate %'',a.val)=0
    and patindex(''% delegate %'',a.val)=0
    and charindex(''('',a.val)>charindex(''function '',a.val)
    ) subs_and_functions

-- =========================================================== scan databases ==

declare cs cursor local for
    select db
    from #dbs
    where 1=1
open cs
while 1=1
    begin
    fetch next from cs into @db
    if @@fetch_status!=0 break

    declare css cursor local for
        select typ,replace([sql],''%db%'',@db)
        from #sql
        where (@tags=0)
        or (@tags=1 and typ=''tags'')
        order by id
    open css
    while 1=1
        begin
        fetch next from css into @typ,@sql
        if @@fetch_status!=0 break

        if @dbg=2 exec sp__prints @typ

        if @typ=''svn'' and @svn=0 continue

        begin try
        exec sp_executesql
                @sql,@params,
                @m1=@m1,@m2=@m2,@m3=@m3,@range=@range,@what=@what,@db=@db,
                @obj=@obj,@xtype=@xtype,@err=@err out,@rows=@rows out,
                @dbg=@dbg
        end try
        begin catch
        select @emsg=error_message()
        raiserror(@emsg,11,1)
        if @dbg>0 exec sp__printf ''error occurred into:''
        else exec sp__printf ''use @dbg=1 or @dbg=2 to see more info''
        if @dbg>0 exec sp__printsql @sql
        end catch
        if @err!=0 or @dbg=2 exec sp__printsql @sql
        if @dbg=2
            begin
            exec sp__printf ''-- found:%d rows'',@rows
            exec sp__select_astext ''select * from #tmp_found''
            exec sp__printf ''''
            truncate table #tmp_found
            end
        end -- sqls
    close css
    deallocate css

    end -- db loop

close cs
deallocate cs


-- show results
display:

if charindex(''|script|'',@opt)>0
    begin
    delete from #tmp_found where obj=''sp__find''
    select @sql=null
    select @sql=isnull(@sql+''|'','''')+obj
    from (
        select distinct obj
        from #tmp_found
        ) tmp
    order by obj
    exec sp__printf ''exec sp__drop ''''%s'''',@simul=0\nGO'',@sql
    declare cs cursor local for
        select distinct obj
        from #tmp_found
        -- where xtype in (''p'',''
        -- select * from fn__xtype()
        order by obj
    open cs
    while 1=1
        begin
        fetch next from cs into @obj
        if @@fetch_status!=0 break
        exec sp__script @obj
        exec sp__printf ''GO''
        end -- while of cursor
    close cs
    deallocate cs

    goto dispose
    end

-- =========================================================== output results ==

if @dbg=1 select * from #sysobjects order by name

if object_id(''tempdb..#sp__find_out'') is null
    begin
    if @dbg!=2
        begin
        if charindex(''|print|'',@opt)=0
        and charindex(''|html|'',@opt)=0
            begin
            select @sql=''
            select distinct db,obj,xtype,[txt1_or_obj],[txt2_or_type],txt3
            from #tmp_found a
            where not obj is null
            order by db,xtype,obj
            ''
            if charindex(''|distinct|'',@opt)!=0
                select @sql=replace(@sql,''[txt1_or_obj],[txt2_or_type],txt3'',''
                    (select top 1 [txt1_or_obj] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt1_or_obj,
                    (select top 1 [txt2_or_type] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt2_or_type,
                    (select top 1 [txt3] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt3
                    '')
            exec(@sql)
            end
        else
            begin
            select @sql=''
                select distinct db,obj,xtype,[txt1_or_obj],[txt2_or_type],txt3
                from #tmp_found a
                where not obj is null
                order by 1,3,2
                ''
            if charindex(''|distinct|'',@opt)!=0
                select @sql=replace(@sql,''[txt1_or_obj],[txt2_or_type],txt3'',''
                    (select top 1 [txt1_or_obj] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt1_or_obj,
                    (select top 1 [txt2_or_type] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt2_or_type,
                    (select top 1 [txt3] from #tmp_found b where b.db=a.db and b.obj=a.obj) txt3
                    '')
            if charindex(''|html|'',@opt)=0
                exec sp__select_astext @sql -- ,@dbg=1
            else
                exec sp__select_astext @sql,@opt=''html'',@header=1
            end
        end
    end
else
    insert #sp__find_out(
        db,obj,xtype,[txt1_or_obj],[txt2_or_type],txt3
        )
    select distinct db,obj,xtype,[txt1_or_obj],[txt2_or_type],txt3
    from #tmp_found
    where not obj is null
    order by db,xtype,obj


dispose:
drop table #tmp_found
drop table #sysobjects
drop table #dbs

goto ret

-- =================================================================== errors ==
err_svn: exec @ret=sp__err ''wrong svn request (%s)'',@proc,@p1=@tmp goto ret

-- ===================================================================== help ==
help:

select @params=@cr+''|''+@lf+''|''+@tab+''|¬''
select @sym=replace(@sym,'' '',''{space}'')
exec sp__str_replace @sym out,@params,''{carrige}'',''{line feed}'',''{tab}'',''[]''
exec sp__usage @proc,''
Scope

    search for word/s between symbols
        >|
         %p1%
         |<

Notes

    * If begin or end with "%" a normal LIKE is used
    * Due limits of 4k''''s  MSSQL store method,
      if a word is split across two chunk (syscomments.text),
      will not found.
    * SVN data are cached into "utility..fnd" table and then refreshed
    automatically before every search.
    * sp__find uses a local "fnd" link to utility.fnd

Parameters

    @what   is the text to search
            or a svn path
    @obj    filter objects by %name% (can be multiple xx|yy|...)
    @xtype  filter for specific type (V,P,F_,etc.)
    @range  default 20, is the len of extracted chars before and after
            point where searched text was found

    @opt    options
            tags        search only info tags
                        (can add to MSSMS keyboard shortcut as
                         ctrl+? -> sp__find @opt=''''tags'''',@what=
                        )
            dbs         search in all databases
            script      script the objects found
            print       show result as text
            html        return a ...
distinct show obj only once and the top 1 of txt1,2,3 ------- svn options ----------------------------------------- clean delete all downloaded data for the specified svn path svn enable update & search from svn cached data unlock force unlock of (probable) broken "already importing" #sp__find_found if exists, the output is stored here and not shown create table #sp__find_out( -- id int identity, db sysname null, obj sysname null, xtype sysname null, [txt1_or_obj] sysname null, [txt2_or_type] sysname null, txt3 sysname null ) @dbg 1: show preselected objects and likes @m1,@m2,@m3 2: print code and relative results Examples exec sp__find "sp__find" exec sp__find "moved" exec sp__find @opt="tags",@what="moved" exec sp__find "[utility]" -- special search, as word "[utility]" exec sp__find "%[utility]" -- this is an error because will search anithing that cotain u,t,i,l,y. exec sp__find "fn__test[1(]" -- search the calls to "fn__test(" or "sp__test1" -- usefull to replace old versions of a function -- ########## SVN ########## -- exec sp__find "svn://svr/SOURCES" -- list content recursivelly exec sp__find "svn://svr/SOURCES/*.vb" -- set and do a download -- or update existing -- list of svn downloads -- '',@p1=@sym select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__find' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__find: -- =============================================================== sp__flds_list select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__flds_list',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=151106 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__flds_list') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__flds_list') with nowait goto skip_sp__flds_list end if @ver>151106 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__flds_list') with nowait goto skip_sp__flds_list end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__flds_list') with nowait if exists( select top 1 null from sys.objects where name='sp__flds_list' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__flds_list] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:table,field,list,quote,name,synonym v:151106\s.zaglio: added collate database_default v:121118\s.zaglio: added quote v:121003\s.zaglio: return list of flds even of a synonym d:121003\s.zaglio: fn__flds_list d:121003\s.zaglio: sp__flds_of d:121003\s.zaglio: sp__search t:sp__flds_list null,''cfg'',@dbg=1,@exclude=''%id%'' t:select * into #cfg from cfg t:sp__flds_list null,''#cfg'',@dbg=1,@exclude=''%id%'' */ CREATE proc sp__flds_list @flds nvarchar(4000) = null out, @obj sysname = null, @sep nvarchar(32) = null, @exclude nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if isnull(@obj,'''')='''' goto help -- ============================================================== declaration == declare -- generic common -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @cols nvarchar(4000),@db sysname,@i int, @sql nvarchar(4000),@oid int, @params nvarchar(512), @end_declare bit -- =========================================================== initialization == -- try to resolve synonym or synonym of synonym... select @flds=null, @obj=case when left(@obj,1)=''#'' then ''tempdb..''+@obj else @obj end, -- @opt1=charindex(''|opt|'',@opt), @sep=isnull(@sep,''|''), @end_declare=1 -- follow synonym exec sp__script_synonym @obj out,@obj,@opt=''path'' select @db=isnull(parsename(@obj,3),db_name()) -- ======================================================== second params chk == -- ===================================================================== body == -- print parsename(''[db..obj]'',1) -- print parsename(''db..[obj]'',1) select @oid=object_id(@obj) if @oid is null return null /* this fn is so slower that is better delete excludes to the end instead of while */ -- collect cols select @sql=replace('' select @flds=isnull(@flds+@sep,'''''''') +case when dbo.fn__token_sql(c.name)=1 or patindex(''''%[^a-z0-9]%'''',c.name collate database_default)>0 then quotename(c.name) else c.name end from [%db%].sys.columns c where c.object_id=@oid and not case c.is_identity when 1 then ''''%id%'''' else c.name collate database_default end in ( select token from fn__str_table(@exclude,@sep) ) order by column_id '',''%db%'',@db) if @dbg=1 exec sp__printsql @sql select @params=''@flds nvarchar(4000) out,@sep nvarchar(32),'' +''@oid int,@exclude nvarchar(4000)'' -- exec sp__printsql @sql exec sp_executesql @sql, @params,@flds=@flds out,@sep=@sep,@exclude=@exclude,@oid=@oid -- sp__flds_list null,''#cfg'',@dbg=1,@exclude=''%id%'' -- select * into #cfg from cfg -- drop table #cfg -- select * from [tempdb].sys.columns c where object_id=object_id(''tempdb..#cfg'') if @dbg=1 exec sp__printf ''-- db:%s, obj:%s, flds:%s'',@db,@obj,@flds -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''write here msg'' goto err err_me2: select @e_msg=''write this %s'',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope return list of flds even of a synonym Notes fields with symbols or reserved words will be quoted Parameters @flds out variable @obj table or synonym @sep separator (default is pipe |) @excludes list os fields to exclude, separated by @sep field %id% is a macro that means "identity field" @opt options (not used) Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__flds_list' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__flds_list: -- ============================================================ sp__flds_of_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__flds_of_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130730 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__flds_of_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__flds_of_test') with nowait goto skip_sp__flds_of_test end if @ver>130730 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__flds_of_test') with nowait goto skip_sp__flds_of_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__flds_of_test') with nowait if exists( select top 1 null from sys.objects where name='sp__flds_of_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__flds_of_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:130730\s.zaglio: test fn__flds_of */ CREATE proc sp__flds_of_test as begin set nocount on declare @ret int,@proc sysname select @ret=0,@proc=object_name(@@procid) declare @d datetime,@i int,@flds nvarchar(4000), @id int,@tbl sysname,@sep char,@exclude nvarchar(4000), @result nvarchar(4000),@st sysname,@new_result nvarchar(4000) if not object_id(''tst_fn__flds_of'') is null drop table tst_fn__flds_of create table tst_fn__flds_of( id int identity, a int, b bit, c nvarchar(max), [_0] uniqueidentifier ) select * into #tst_fn__flds_of from tst_fn__flds_of declare @test table( id int primary key, tbl sysname, sep char, exclude sysname null, result nvarchar(4000) ) insert @test select 1,''#tst_fn__flds_of'','','',null,''id,a,b,c,_0'' insert @test select 2,''#tst_fn__flds_of'','','',''id,a'',''b,c,_0'' insert @test select 3,''#tst_fn__flds_of'','','',''%id%'',''a,b,c,_0'' insert @test select 4,''tst_fn__flds_of'','','',''a,%id%'',''b,c,_0'' insert @test select 5,''unk'','','',null,null declare cs cursor local for select id,tbl,sep,exclude,result from @test open cs while 1=1 begin fetch next from cs into @id,@tbl,@sep,@exclude,@result if @@fetch_status!=0 break select @new_result=dbo.fn__flds_of(@tbl,@sep,@exclude) if @new_result=@result or @new_result is null and @result is null select @st=''ok'' else select @st=''ko'' exec sp__printf ''%d:%s\nexpected:%s\nresult:%s'', @id,@st,@result,@new_result if @st=''ko'' select @ret=1 end -- cursor cs close cs deallocate cs exec sp__printf '''' exec sp__elapsed @d out select @i=1000 while @i>0 select @flds=dbo.fn__flds_of(''tst_flds_of'','','',null), @i=@i-1 exec sp__elapsed @d out,''after 1000 loops of v:120413 with ident'' select @i=1000 while @i>0 select @flds=dbo.fn__flds_of(''tst_flds_of'','','',''%id%''), @i=@i-1 exec sp__elapsed @d out,''after 1000 loops of v:120413 without ident'' -- before 120413: 1s 63ms -- after 120413: 1s 540ms and 2s 433ms without drop table #tst_fn__flds_of drop table tst_fn__flds_of if @ret!=0 exec sp__err ''test failed'',@proc return @ret end -- sp__flds_of_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__flds_of_test: -- ====================================================================== sp__fn select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__fn',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090707.1055 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__fn') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__fn') with nowait goto skip_sp__fn end if @ver>090707.1055 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__fn') with nowait goto skip_sp__fn end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__fn') with nowait if exists( select top 1 null from sys.objects where name='sp__fn' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__fn] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090707.1055\s.zaglio: revision v:090630.1055\s.zaglio: utility per chiamare velocemente le FN_... t:sp__fn ''address'' */ CREATE proc [dbo].[sp__fn] @name sysname=null, @v1 sql_variant=null,@v2 sql_variant=null,@v3 sql_variant=null as begin set nocount on declare @sql nvarchar(4000),@ename sysname,@msg nvarchar(4000) declare @p table (id int identity, param sysname) declare @i int,@n int,@params nvarchar(4000),@param sysname if @name is null goto help -- select xtype from sysobjects group by xtype select @ename=name from sysobjects where name like @name and xtype in (''TF'',''IF'',''FN'') if @ename is null select @ename=name from sysobjects where name like ''%''+@name+''%'' and xtype in (''TF'',''IF'',''FN'') if @ename is null goto err_name exec sp__usage @ename insert into @p(param) select name from syscolumns where id=object_id(@ename) and left(name,1)=''@'' order by colid select @params='''',@i=min(id),@n=max(id) from @p while (@i<=@n) select @params=@params+''null''+case when @i<@n then '','' else '''' end,@i=@i+1 set @sql=''select * from ''+@ename+''(''+@params+'')'' select lower(@sql) as cmd_line exec(@sql) goto ret err_name: select @msg=''function name not found'' goto ret help: exec sp__printf ''specificare nome o contenuto funzione'' exec sp__printf ''nb:procedura da ultimare'' ret: if not @msg is null exec sp__printf @msg end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__fn: -- ================================================================== sp__format select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__format',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130624 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__format') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__format') with nowait goto skip_sp__format end if @ver>130624 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__format') with nowait goto skip_sp__format end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__format') with nowait if exists( select top 1 null from sys.objects where name='sp__format' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__format] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file k:format,test g:utility v:130624\s.zaglio: added 0<3 into test to allow out usage v:130510\s.zaglio: added sample for 01 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare @id int,@d datetime,@drop bit -- drop table #tests if object_id(''tempdb..#tests'') is null begin create table #tests( id int identity, val sql_variant, fmt nvarchar(128), ln int, expected nvarchar(4000), comment nvarchar(4000), result nvarchar(4000) ) select @drop=1 end else select @drop=0 -- =========================================================== initialization == select @d=''2012-08-21T16:28:11.000'' truncate table #tests insert #tests select @d, ''hhmm'', 4, ''???'', null, null insert #tests select @d, ''yyyy'', null, year(@d), null, null insert #tests select ''0930'', ''hhmm'', 4, ''0930'', null, null insert #tests select @d, ''HHMMSS'', 6, ''162811'', null, null insert #tests select @d, ''DD/MM/YYYY HH:MM:SS'', null, ''21/08/2012 16:28:11'', null, null insert #tests select @d, ''YYYYMMDD_HHMMSS'',null, ''20120821_162811'', null, null insert #tests select @d, ''YYYYMMDDHHMMSS'',null, ''20120821162811'', null, null insert #tests select ''strip.n0t''''AN: ;_chrs'', ''AN'', null, ''strip_n0t_AN____chrs'', ''normalize light'', null insert #tests select ''..strip.n0t''''AN: ;_chrs..'', ''ANs'', null, ''strip_n0t_AN_chrs'', ''normalize heavy'', null insert #tests select 123, ''0<'', 10, ''0000000123'', ''right padding with 0'', null insert #tests select 123.435, ''0<2'', 10, ''0000012344'', ''right padding with 0 and round and decimals'', null insert #tests select 123.435, ''0<3'', 10, ''0000123435'', ''right padding with 0 and round and decimals'', null insert #tests select 123, ''$<'', 10, ''0000123.00'', ''right money padding with 0'', null insert #tests select ''fn__format'', ''=<'', 20, ''==========fn__format'', ''right padding with ='', null insert #tests select ''fn__format'', ''=< '', 20, ''========= fn__format'', ''right padding with = and a char before the name'', null insert #tests select ''1239'', ''[eng]'', null, ''One thousand two hundred thirty-nine'', null, null insert #tests select 1.104e+006, ''0<'', 10, ''0001104000'', ''right padding with 0'', null insert #tests select ''aàsòì°fd'', ''^'', null, ''aa''''so''''i''''.fd'', ''transform accent'', null insert #tests select ''test'', ''^'', null, ''test'', null, null insert #tests select ''01021972'', ''@5678-34-12'', null, ''1972-02-01'',''relocate chars positions'', null insert #tests select ''1234567890AB...'', ''@edcba0987654321'', null, ''...BA0987654321'',''relocate chars positions'', null update #tests set result=cast(dbo.fn__format(val,fmt,ln) as nvarchar(4000)) --insert #tests select ''REP05_DELIVERY'', ''|HIS*'', null, ''HIS05_DELIVERY'' -- ======================================================== second params chk == if (@drop=0 or @val is null or @fmt is null) -- and @opt=''||'' goto help -- ===================================================================== body == print dbo.fn__format(@val,@fmt,@len) goto ret -- =================================================================== errors == /* err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret */ -- ===================================================================== help == help: if @drop=0 goto skip exec sp__usage @proc,'' Scope give help about fn__format and test backward compatibility Notes formats covered by CONVERT like YYYYMMDD(112),YYMMDD(12) are not covered. Parameters #tests optional table where returns tests create table #tests( id int identity, val sql_variant, fmt nvarchar(128), ln int, expected nvarchar(4000), comment nvarchar(4000), result nvarchar(4000) ) @val is the value passed to be formatted and the result @fmt is the format (see below) @len depending on @fmt can be null or a generic length @opt options(not used) -- List of formats with example and expected results -- '' exec sp__select_astext '' select id ,val ,fmt,ln ,expected ,result ,comment from #tests order by id '' skip: select top 1 @id=id from #tests where result!=expected and expected!=''???'' if not @id is null exec @ret=sp__err ''wrong result from fn__format in test %d'',@proc,@p1=@id else select @ret=-1 if @drop=1 drop table #tests -- select * from #tests -- ===================================================================== exit == ret: return @ret end -- proc sp__format' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__format: -- ===================================================================== sp__ftp select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__ftp',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140107 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__ftp') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__ftp') with nowait goto skip_sp__ftp end if @ver>140107 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__ftp') with nowait goto skip_sp__ftp end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__ftp') with nowait if exists( select top 1 null from sys.objects where name='sp__ftp' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__ftp] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140107\s.zaglio: adaptation to 64bit OS v:130604\s.zaglio: small improvements near #files cmds v:130603\s.zaglio: adapted to fn__ftp_parse_lst v:120620\s.zaglio: added ms.svr.dir output->#files v:120618\s.zaglio: a bug near winscp date v:120503\s.zaglio: winscp automatic if hostkey specified v:120502\s.zaglio: added hostkey parameter,help and files correct list v:120427\s.zaglio: tested winscp and correct a bug near console output r:120426\s.zaglio: adding support for winscp v:120413\s.zaglio: adopted @ftpout v:120404\s.zaglio: a bug near cmd #files (do not modify #ftpcmd) v:120204\s.zaglio: added support to #files for non unix svr v:120111\s.zaglio: added listing to #files v:111122\s.zaglio: added error 550 (cd) v:110715.1050\s.zaglio: added @cmd v:110530\s.zaglio: commented gen of ftpout and added trace of not managed error "file not found" v:110527\s.zaglio: added result ok rename ok v:110512\s.zaglio: added tests and delete ok v:110330\s.zaglio: call ms ftp.exe and execute content of #ftpcmd t:sp__ftp @opt=''check'' */ CREATE proc sp__ftp @login nvarchar(1024)=null, @cmds nvarchar(4000)=null, @opt sysname=null, @dbg int=0 as begin set nocount on set language us_english -- this dont change caller language -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @login is null or (object_id(''tempdb..#ftpcmd'') is null and @dbg=0 and @cmds is null) goto help -- ============================================================== declaration == declare @tmp nvarchar(1024),@crlf nvarchar(2), @svr sysname,@db sysname,@uid sysname,@pwd sysname, @ftp_svr sysname,@ftp_uid sysname,@ftp_pwd sysname,@ftp_path sysname, @ftp_key sysname,@winscp_path nvarchar(512), @i int,@ftp_cmd sysname, @file_path nvarchar(1024),@cmd nvarchar(4000),@file sysname, @files bit,@drop_files bit,@winscp bit, @pf nvarchar(512) -- path find declare @ftpout table(lno int identity, line nvarchar(4000)) declare @ftp_msg table(code nvarchar(3)) if left(@cmds,6)=''#files'' begin -- if @cmds results null, are used commands of #ftpcmd select @files=1,@cmds=''dir ''+nullif(substring(@cmds,8,128),'''') if object_id(''tempdb..#files'') is null begin select @drop_files=1 create table #files ( id int identity, rid int null, -- for subdirs [flags] smallint, -- if &32=32 is a [key] nvarchar(256), -- obj name dt datetime, -- creation date n int null -- size in bytes ) end else select @drop_files=0 end -- files cmd else select @files=0 -- ok msg: do not return error insert @ftp_msg(code) select ''150'' -- Opening ASCII mode data connection for file list. union select ''200'' -- command ok union select ''220'' -- welcome or identification "Microsoft FTP Service" union select ''226'' -- Transfer complete. union select ''221'' -- quitted union select ''230'' -- User XXXX logged in. union select ''250'' -- file deleted succesfully union select ''331'' -- Password required for wcarevivisol-mi3. union select ''350'' -- File exists, ready for destination name. (rename) create table #ftpsrc(lno int identity, line nvarchar(4000)) -- =========================================================== initialization == select @crlf=crlf, @winscp = charindex(''|winscp|'',@opt) from fn__sym() select @ftp_svr=dbo.fn__str_at(@login,''|'',1), @ftp_uid=dbo.fn__str_at(@login,''|'',2), @ftp_pwd=dbo.fn__str_at(@login,''|'',3), @ftp_path=dbo.fn__str_at(@login,''|'',4), @ftp_key=dbo.fn__str_at(@login,''|'',5) -- ======================================================== second params chk == if coalesce(@ftp_key,'''')!='''' select @winscp=1 if @winscp=1 begin select @winscp_path=''winscp\winscp.com'' exec sp__os_whereis @winscp_path out if @winscp_path is null goto err_wnf -- winscp not found end -- ===================================================================== body == -- write the command file exec sp__get_temp_dir @tmp out select @file=''tmp_''+replace(convert(sysname,newid()),''-'',''_'')+''.txt'' select @file_path=@tmp+''\''+@file if @dbg>0 exec sp__printf ''svr:%s\nuid:%s\npwd:%s\npath:%s\nkey:%s'', @ftp_svr,@ftp_uid,@ftp_pwd,@ftp_path,@ftp_key -- ftp login commands if @winscp=0 begin insert #ftpsrc(line) values(''open ''+@ftp_svr) insert #ftpsrc(line) values(@ftp_uid) insert #ftpsrc(line) values(@ftp_pwd) end else insert #ftpsrc(line) select ''open ''+@ftp_uid+'':''+@ftp_pwd+''@''+@ftp_svr+ case when coalesce(@ftp_key,'''')!='''' then '' -hostkey="''+@ftp_key+''"'' else '''' end --insert #ftpsrc(line) values(''prompt'') insert #ftpsrc(line) values(''binary'') if coalesce(@ftp_path,'''')!='''' insert #ftpsrc(line) values(''cd "''+@ftp_path+''"'') insert #ftpsrc(line) values(''lcd "''+@tmp+''"'') if not object_id(''tempdb..#ftpcmd'') is null and (@files=0 or @cmds is null) insert #ftpsrc(line) select line from #ftpcmd order by lno if not @cmds is null begin if @files=1 insert #ftpsrc(line) select @cmds else insert #ftpsrc(line) select token from fn__str_table(@cmds,''\\n'') order by pos end if @dbg=2 begin insert #ftpsrc(line) values(''put "''+@file_path+''"'') insert #ftpsrc(line) values(''ls'') insert #ftpsrc(line) values(''delete "''+@file+''"'') end insert #ftpsrc(line) values(''bye'') exec sp__file_write @file_path,@table=''#ftpsrc'',@addcrlf=1 /* 120503\s.zaglio: if @dbg>0 begin select @cmd=''dir "%s" & type "%s"'' exec sp__str_replace @cmd out,''%s'',@file_path exec master..xp_cmdshell @cmd end */ -- now ftp -- if @dbg=1 if @winscp=0 select @cmd=''ftp -v -d -s:"%file%" ''-- +@ftp_svr else select @cmd=@winscp_path+'' /script="%file%"'' -- else -- select @cmd=''ftp -v -s:"%file%" %svr%'' exec sp__str_replace @cmd out,''%file%|%svr%'',@file_path,@ftp_svr if @dbg>0 exec sp__printf ''cmd:%s'',@cmd -- ########################## -- ## -- ## call external ftp util -- ## -- ######################################################## insert @ftpout(line) exec @ret=master..xp_cmdshell @cmd -- it looks like ftp client(or iis server) add a #13 at the end of each line so i simply drop all #13 update @ftpout set line=replace(rtrim(line),char(13),'''') -- manage not managed errors if exists( select null from @ftpout where (lno>@i or @i is null) and (line like ''%connection refused'' or line like ''unknown host%'' or line like ''host sconosciuto%'' or line like ''accesso non riuscito%'' or line like ''invalid command%'' or line like ''comando non valido'' or line like ''%file not found'' or line like ''%file non trovato'' ) ) select @ret=-3 if exists( select null from @ftpout where 1=1 and isnumeric(left(line,3))=1 and substring(line,4,1)='' '' -- XXX_ and not left(line,3) in (select code from @ftp_msg) ) begin -- select * from ftpout /* 110530\s.zaglio: if object_id(''ftpout'') is null create table ftpout(lno int, code nvarchar(3),err bit,line nvarchar(4000)) insert ftpout select lno,left(line,3) code,case when left(line,3) in (select code from @ftp_msg) then 1 else 0 end as err,line from #ftpout */ select @ret=-2 end if @dbg>0 begin select lno, case when isnumeric(left(line,3))=1 and substring(line,4,1)='' '' -- XXX_ and not left(line,3) in (select code from @ftp_msg) then ''***'' else null end as err, line into #ftpoutdbg from @ftpout order by lno exec sp__select_astext ''select * from #ftpoutdbg order by lno'',@header=1 drop table #ftpoutdbg end if @ret=0 and @files=1 begin declare @lng sysname select @lng=@@language set language english -- for jan, ... insert #files([key],flags,dt,n) select [name],case dir when ''d'' then 32 else 0 end, convert(datetime,[timestamp],100),size from @ftpout f cross apply fn__ftp_parse_list(f.lno,f.line,default) set language @lng end -- files -- remove temp -- if @dbg>0 goto skip_del -- enable this only temporary because leave public tmp select @cmd=''del "''+@file_path+''"'' exec master..xp_cmdshell @cmd,no_output skip_del: if @files=1 and (@drop_files=1 or @dbg=1) begin if @dbg=1 exec sp__select_astext ''select * from #files'',@header=1 if @drop_files=1 begin select * from #files drop table #files end end if @dbg>0 exec sp__select_astext ''select * from #ftpsrc order by lno'',@header=1 if object_id(''tempdb..#ftpout'') is null select line from @ftpout order by lno else insert #ftpout(line) select line from @ftpout order by lno drop table #ftpsrc goto ret -- =================================================================== errors == err_wnf: exec @ret=sp__err ''WINSCP not found'',@proc; goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope wrapper for MS ftp.exe and execute content of #ftpcmd and return results into #ftpout (if exists or are printed) Parameters @login ftp_svr|uid|pwd|[ftp_path]|[hostkey] @cmds test or fast command (can be multiple if separated by \\n) Accept special command for files listing #files or #files:pattern (use *) if present, stores results into create table #files ( id int identity, rid int null, -- for subdirs [flags] smallint, -- if &32=32 is a [key] nvarchar(256), -- obj name dt datetime, -- creation date n int null -- size in bytes ) (see sp__dir) @opt options description winscp force use of winscp, automatic if hostkey is specified @dbg 1=test connection and show dbg info 2=test upload list and delete #ftpcmd list of ftp commands to execute #ftpout (optional) append the output to this (keeping original data) return 0 if ok, -1 if help, -2 if a non ok replies ok replies are 200 type set to I 220 Service ready for new user. 221 Service closing control connection. Logged out if appropriate. 230 User logged in, proceed. 250 file deleted succesfully 331 User name okay, need password. 350 File exists, ready for destination name. (rename) 550 failed change directory (cd) For all others see http://www.ietf.org/rfc/rfc2821.txt Notes create table #ftpcmd(lno int identity,line nvarchar(4000)) create table #ftpout(lno int identity,line nvarchar(4000)) Examples sp__ftp "10.0.0.2|uid|pwd","ls" sp__ftp "10.0.0.1|uid|pwd||ssh-rsa 2048 5c:a4:...","ls",@opt="winscp" '' select @winscp_path=''winscp\winscp.com'' exec sp__os_whereis @winscp_path out if not @winscp_path is null exec sp__printf ''-- winscp path: %s'',@winscp_path select @winscp_path=''ftp.exe'' exec sp__os_whereis @winscp_path out if not @winscp_path is null exec sp__printf ''-- ftp path: %s'',@winscp_path select @ret=-1 -- ===================================================================== exit == ret: if @dbg>0 exec sp__printf ''return: %d'',@ret return @ret end -- proc sp__ftp' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__ftp: -- ============================================================== sp__ftp_manage select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__ftp_manage',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130628 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__ftp_manage') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__ftp_manage') with nowait goto skip_sp__ftp_manage end if @ver>130628 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__ftp_manage') with nowait goto skip_sp__ftp_manage end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__ftp_manage') with nowait if exists( select top 1 null from sys.objects where name='sp__ftp_manage' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__ftp_manage] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:ftp,manage,download,upload,delete,rename,ok,err v:130628\s.zaglio: bug near path v:130626\s.zaglio: bug near rename r:130614\s.zaglio: refined r:130302\s.zaglio: common ftp functionality */ create proc sp__ftp_manage @login nvarchar(1024) = null, @path nvarchar(1024) = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @temp nvarchar(512),@cmd nvarchar(4000), @files bit,@ftpcmd bit,@ftpout bit, -- if relative table exists @flg_download smallint,@flg_upload smallint, @flg_delete smallint,@flg_ok smallint, @flg_err smallint, @end_declare bit -- =========================================================== initialization == select @path=nullif(@path,''''), @files=isnull(object_id(''tempdb..#files''),0), @ftpout=isnull(object_id(''tempdb..#ftpout''),0), @ftpcmd=isnull(object_id(''tempdb..#ftpcmd''),0), @flg_download=[files.download], @flg_upload=[files.upload], @flg_delete=[files.delete], @flg_ok=[files.ok], @flg_err=[files.err], @end_declare=1 from flags -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @login is null or @files=0 goto help -- =============================================================== #tbls init == if @ftpcmd=0 create table #ftpcmd(lno int identity primary key,line nvarchar(4000)) if @ftpout=0 create table #ftpout(lno int identity primary key,line nvarchar(4000)) -- ===================================================================== body == if charindex(''%temp%'',@path)>0 -- if null invalidate all statement begin exec sp__get_temp_dir @temp out select @path=replace(@path,''%temp%'',@temp) end if @path!='''' begin insert #ftpcmd select ''lcd "''+@path+''"'' -- if nothing to upload, drop and create temp path if not exists(select top 1 null from #files where flags&@flg_upload!=0) begin select @cmd=''del /s/q/f ''+@path+ ''&rmdir /s/q ''+@path+ ''&mkdir ''+@path exec xp_cmdshell @cmd,no_output end end -- default order: download, delete, rename, upload insert #ftpcmd select ''get "''+[key]+''"'' from #files where flags&@flg_download!=0 insert #ftpcmd select ''del "''+[key]+''"'' from #files where flags&@flg_delete!=0 insert #ftpcmd select ''ren "''+[key]+''" "''+[key]+ case when flags&@flg_ok!=0 then ''.ok'' when flags&@flg_err!=0 then ''.err'' end+''"'' from #files where flags&(@flg_ok|@flg_err)!=0 -- upload as temp files insert #ftpcmd select ''put "''+[key]+''" "tmp_''+[key]+''.tmp"'' from #files where flags&@flg_upload!=0 -- rename uploaded temp insert #ftpcmd select ''ren "''+[key]+''" "tmp_''+[key]+''.tmp" "''+[key]+''"'' from #files where flags&@flg_upload!=0 if @dbg in (0,2) begin exec @ret=sp__ftp @login if @dbg>1 exec sp__print_table ''#ftpout'' end else exec sp__print_table ''#ftpcmd'' -- ================================================================== dispose == dispose: if @ftpcmd=0 drop table #ftpcmd if @ftpout=0 drop table #ftpout goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope manage common ftp functionality as upload,download,rename,delete,etc. Parameters #files list of files according to sp__ftp settings flags field with flags.[files.*] we can simply manage files #ftpcmd optional (caller must manage the fill/unfill) #ftpout optional (caller must manage the cleaning) @login login info according to sp__ftp @login @path optional path where found files to download/upload @opt options (not used) @dbg 1=show ftp cmds without execute it 2=execute ftp cmds and show ftp out Examples create table #files .... exec sp__ftp "127.0.0.1|usr|pwd","#files:*" update #files set flags=flags|flg.[files.del] from flags exec sp__ftp_manage "127.0.0.1|usr|pwd" -- this will delete all files '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__ftp_manage' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__ftp_manage: -- ================================================================= sp__geocode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__geocode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120124 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__geocode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__geocode') with nowait goto skip_sp__geocode end if @ver>120124 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__geocode') with nowait goto skip_sp__geocode end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__geocode') with nowait if exists( select top 1 null from sys.objects where name='sp__geocode' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__geocode] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:gps,coords,street v:120124\s.zaglio: ask google for coords c:origin http://www.sqlservercentral.com/articles/geocode/70061/ */ CREATE proc sp__geocode @opt sysname = null, @dbg int = null as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if object_id(''tempdb..#addr'') is null goto help -- ============================================================== declaration == declare @address varchar(80) , @city varchar(40) , @state varchar(40) , @country varchar(40) , @postalcode varchar(20), @county varchar(40) , @gpslatitude numeric(9,6) , @gpslongitude numeric(9,6), @mapurl varchar(1024) declare @url varchar(max), @response varchar(8000), @xml xml, @obj int , @hr int , @httpstatus int , @error varchar(max), @tmp nvarchar(4000) -- =========================================================== initialization == -- ======================================================== second params chk == -- ===================================================================== body == -- ########################## -- ## -- ## be carefull with upcase letters on xml path -- ## -- ######################################################## exec @hr = sp_oacreate ''MSXML2.ServerXMLHttp'', @obj out if @hr!=0 goto err_ole declare cs cursor local for select gpslatitude, gpslongitude, city, [state] , postalcode , [address], country , county, mapurl , error from #addr where 1=1 open cs while 1=1 begin fetch next from cs into @gpslatitude, @gpslongitude, @city, @state, @postalcode, @address, @country, @county, @mapurl, @error if @@fetch_status!=0 break exec sp__printf ''addr:%s, state:%s'',@address,@state select @url = ''http://maps.google.com/maps/api/geocode/xml?sensor=false&address='' + case when @address is not null then @address else '''' end + case when @city is not null then '', '' + @city else '''' end + case when @state is not null then '', '' + @state else '''' end + case when @postalcode is not null then '', '' + @postalcode else '''' end + case when @country is not null then '', '' + @country else '''' end select @url = replace(@url, '' '', ''+'') if @dbg=1 begin select @tmp=cast(@url as nvarchar(4000)) exec sp__printf ''get url:%s'',@tmp end exec @hr = sp_oamethod @obj, ''open'', null, ''GET'', @url, false if @hr!=0 goto err exec @hr = sp_oamethod @obj, ''setRequestHeader'', null, ''content-type'', ''application/x-www-form-urlencoded'' if @hr!=0 goto err exec @hr = sp_oamethod @obj, ''send'', null, '''' if @hr!=0 goto err select @httpstatus=null,@response=null,@xml=null exec @hr = sp_oagetproperty @obj, ''status'', @httpstatus out if @hr!=0 goto err -- exec @hr = sp_oagetproperty @obj, ''responseXML.xml'', @response out exec @hr = sp_oagetproperty @obj, ''responseText'', @response out err: if (@error is not null) or (@httpstatus <> 200) or (@hr!=0) begin exec sp_oageterrorinfo @obj, @error out, @tmp out if @httpstatus <> 200 and @hr=0 select @error = ''error in spgeocode: '' + isnull(@error, ''http result is: '' + cast(@httpstatus as varchar(10))) else select @error=cast(@hr as sysname)+'':''+isnull(@error,''?'')+'' - ''+isnull(@tmp,''?'') goto skip end select @xml = cast(@response as xml) if @dbg>1 begin select @tmp=cast(@xml as nvarchar(4000)) exec sp__printf ''xml:%s'',@tmp end select @gpslatitude = @xml.value(''(/GeocodeResponse/result/geometry/location/lat) [1]'', ''numeric(9,6)''), @gpslongitude = @xml.value(''(/GeocodeResponse/result/geometry/location/lng) [1]'', ''numeric(9,6)''), @city = @xml.value(''(/GeocodeResponse/result/address_component[type="locality"]/long_name) [1]'', ''varchar(40)''), @state = @xml.value(''(/GeocodeResponse/result/address_component[type="administrative_area_level_1"]/short_name) [1]'', ''varchar(40)''), @postalcode = @XML.value(''(/GeocodeResponse/result/address_component[type="postal_code"]/long_name) [1]'', ''varchar(20)'') , @country = @XML.value(''(/GeocodeResponse/result/address_component[type="country"]/short_name) [1]'', ''varchar(40)'') , @county = @XML.value(''(/GeocodeResponse/result/address_component[type="administrative_area_level_2"]/short_name) [1]'', ''varchar(40)'') , @address = ISNULL(@XML.value(''(/GeocodeResponse/result/address_component[type="street_number"]/long_name) [1]'', ''varchar(40)''), ''???'') + '' '' + ISNULL(@XML.value(''(/GeocodeResponse/result/address_component[type="route"]/long_name) [1]'', ''varchar(40)''), ''???''), @mapurl = ''http://maps.google.com/maps?f=q&hl=en&q='' + cast(@gpslatitude as varchar(20)) + ''+'' + cast(@gpslongitude as varchar(20)) skip: update #addr set gpslatitude =@gpslatitude, gpslongitude =@gpslongitude, city =@city, [state] =@state, postalcode =@postalcode, [address] =@address, country =@country, county =@county, mapurl =@mapurl, error =@error where current of cs end -- while of cursor close cs deallocate cs exec @hr = sp_oadestroy @obj goto ret -- =================================================================== errors == err_ole: exec @ret=sp__err ''object creation error'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope fill a table with corrected addresses and coords from google maps Parameters #addr is the table with addresses. Must be specified at least address,city and state create table #addr( [address] varchar(80) null, city varchar(40) null, [state] varchar(40) null, country varchar(40) null, postalcode varchar(20) null, county varchar(40) null, gpslatitude numeric(9,6) null, gpslongitude numeric(9,6) null, mapurl varchar(1024) null, error varchar(max) null ) Examples insert #addr(address,city,state) select "1234 N. Main Street","Sant Ana","CA" union select "219 E Washington Ave","Sant Ana","CA" union select "219 E Washington Ave",null,"CA" -- this cause an error -- but the url would work exec sp__geocode select * from #addr '' -- ===================================================================== exit == ret: return @ret end -- sp__geocode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__geocode: -- ================================================================= sp__get_env select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__get_env',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__get_env') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__get_env') with nowait goto skip_sp__get_env end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__get_env') with nowait goto skip_sp__get_env end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__get_env') with nowait if exists( select top 1 null from sys.objects where name='sp__get_env' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__get_env] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091018\s.zaglio: added help v:090910\s.zaglio: get os env var t:declare @tmp nvarchar(128) exec sp__get_env @tmp out,''allusersprofile'' print @tmp */ CREATE proc [dbo].[sp__get_env] @val sysname=null output, @var sysname=null as begin set nocount on create table #lines (lno int identity, line nvarchar(4000)) declare @cmd nvarchar(4000), @crlf nchar(2) set @cmd=''set'' set @val=null insert #lines (line) exec master.dbo.xp_cmdshell @cmd--,no_output -- if use this don''t work if @var is null select * from #lines else select @val=isnull(rtrim(substring(line,charindex(''='',line)+1,256)),'''') from #lines where line like @var+''=%'' drop table #lines if @var is null exec sp__usage ''sp__get_env'' end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__get_env: -- ============================================================ sp__get_temp_dir select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__get_temp_dir',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131208 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__get_temp_dir') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__get_temp_dir') with nowait goto skip_sp__get_temp_dir end if @ver>131208 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__get_temp_dir') with nowait goto skip_sp__get_temp_dir end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__get_temp_dir') with nowait if exists( select top 1 null from sys.objects where name='sp__get_temp_dir' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__get_temp_dir] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility d:131208\s.zaglio:sp__get_tmp v:131208\s.zaglio:added opt TF and TEST v:130830.1000\s.zaglio:remove final \ if exists and added help v:100402\s.zaglio:returned dir is without final \\ v:090910\s.zaglio:adapted to use sp__get_env v:080414\s.zaglio:creation t:sp__get_temp_dir @opt=''tf|test'' */ CREATE proc [dbo].[sp__get_temp_dir] @dir nvarchar(512) = null output, @opt sysname = null as begin set nocount on declare @tf bit,@test bit if not @opt is null begin select @opt=''|''+@opt+''|'' select @tf=charindex(''|tf|'',@opt),@test=charindex(''|test|'',@opt) end else select @tf=0,@test=0 exec sp__get_env @dir out,''temp'' if right(@dir,1)=''\'' select @dir=left(@dir,len(@dir)-1) if @tf=1 select @dir=@dir+''\tmp_''+replace(convert(sysname,newid()),''-'',''_'') if @test=0 and (@@nestlevel>1 -- in remote is 1 even if called by a local sp ... or dbo.fn__isconsole()=0) -- ... this solve the above problem return if @test=1 begin exec sp__printf ''%s'',@dir return end declare @proc sysname select @proc=object_name(@@procid) exec sp__usage @proc,'' Scope return value of OS "temp" environment variable without last \. Notes if called under a sp, this help will not shown Parameters @dir is the output var that will contain the path @opt options tf attach a temp file name from newid() test print output Example declare @tmp nvarchar(512) exec %proc% @tmp out print @tmp -- will return "%p1%" '',@p1=@dir end -- sp__get_temp_dir' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__get_temp_dir: -- =================================================================== sp__getid select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__getid',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080817 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__getid') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__getid') with nowait goto skip_sp__getid end if @ver>080817 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__getid') with nowait goto skip_sp__getid end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__getid') with nowait if exists( select top 1 null from sys.objects where name='sp__getid' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__getid] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080817\S.Zaglio: complete alternativelly id or name t: declare @id int,@ido sysname select @ido=convert(sysname,object_id(''sysobjects'')) exec sp__getid @ido out,''sysobjects'',''name'',''id'',@dbg=1 if @ido is null print ''not found by id'' else print @ido exec sp__getid @ido out,''sysobjects'',''name'',''id'',@id_only=0,@dbg=1 if @ido is null print ''not found by id'' else print @ido select @ido=''sysobjects'' exec sp__getid @ido out,''sysobjects'',''name'',''id'',@dbg=1 if @ido is null print ''not found by name'' else print @ido */ CREATE proc sp__getid @param sysname=null out, @table sysname=null, @name sysname=null, @id sysname=null, @id_only bit=1, @dbg bit=0 as begin set nocount on declare @r int exec @r=sp__chknulls @param,@table,@name,@id if @r=1 goto help declare @sql nvarchar(4000) if isnumeric(@param)=1 begin -- verify anyway that exists if @dbg=1 and @id_only=1 print ''id->id'' if @dbg=1 and @id_only=0 print ''id->name'' if @id_only=1 select @sql=''select @id=convert(sysname,%id%) from %tbl% where %id%=convert(int,%param%)'' else select @sql=''select @id=%name% from %tbl% where %id%=convert(int,%param%)'' exec sp__str_replace @sql out,''%id%|%tbl%|%name%|%param%'',@id,@table,@name,@param exec sp_executesql @sql,N''@id sysname out'',@id=@param out end else begin -- get id from name if @dbg=1 print ''name->id'' select @sql=''select @id=convert(sysname,%id%) from %tbl% where %name%=''''%param%'''''' exec sp__str_replace @sql out,''%id%|%tbl%|%name%|%param%'',@id,@table,@name,@param exec sp_executesql @sql,N''@id sysname out'',@id=@param out end goto ret help: exec sp__usage ''sp__getid'' ret: end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__getid: -- =================================================================== sp__group select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__group',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090507.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__group') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__group') with nowait goto skip_sp__group end if @ver>090507.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__group') with nowait goto skip_sp__group end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__group') with nowait if exists( select top 1 null from sys.objects where name='sp__group' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__group] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090507.1000\s.zaglio: stored of example t:sp__group ''utility'',''sp__group'' */ CREATE proc sp__group @group sysname=null, @objs sysname=null, --- objs to add @order int=null, @parent sysname=null, @chk sysname=null, @dbg bit=0 as begin set nocount on declare @r int raiserror(''todo and rethinking'',18,1) end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__group: -- ==================================================================== sp__hkey select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__hkey',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130929 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__hkey') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__hkey') with nowait goto skip_sp__hkey end if @ver>130929 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__hkey') with nowait goto skip_sp__hkey end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__hkey') with nowait if exists( select top 1 null from sys.objects where name='sp__hkey' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__hkey] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:horizontal,keys, r:130929\s.zaglio: convert a list of keys in horizontal t:sp__hkey_test */ CREATE proc sp__hkey @column nvarchar(4000) = null, @hkey nvarchar(max) = null out, @opt sysname = null, @dbg int=0 as begin try set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @data nvarchar(max),@sep char,@nolist bit -- =========================================================== initialization == select @column=nullif(@column,''''),@sep=''|'',@nolist=charindex(''|nolist|'',@opt) -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @column is null goto help -- =============================================================== #tbls init == create table #tmp(ukey sysname) -- ===================================================================== body == select @column=''insert into #tmp select * from (''+@column+'') a'' exec sp__printf ''%s'',@column exec(@column) select @data= stuff( (select @sep + ukey from #tmp for xml path(''''), type ).value(''(./text())[1]'',''nvarchar(max)'') , 1, len(@sep), '''') select @hkey=replace(@data,@sep,'''') if @nolist=1 goto dispose ;with pieces(pos, start, [stop]) as ( select cast(1 as int), cast(1 as int), charindex(@sep, @data) union all select cast(pos + 1 as int), cast([stop] + 1 as int), charindex(@sep, @data, [stop] + 1) from pieces where [stop] > 0 ) select -- row_number() over(order by (select 0)) row, pos, substring(@data, start, case when [stop] > 0 then [stop]-start else 4000 end ) as token, start, substring(@hkey,start-pos+1,10) ex from pieces option (maxrecursion 0) -- ================================================================== dispose == dispose: drop table #tmp goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope [write here a short desc] Parameters [param] [desc] @column sql select of column key @opt options nolist do not output list os positions @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples sp__hkey "select ukey from table" '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__hkey' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__hkey: -- ==================================================================== sp__info select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131107.1200 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info') with nowait goto skip_sp__info end if @ver>131107.1200 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info') with nowait goto skip_sp__info end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info') with nowait if exists( select top 1 null from sys.objects where name='sp__info' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131107.1200\s.zaglio: removed list of objs when one found and about sys... objs v:131001,130906\s.zaglio: added shortcut info v:110926\s.zaglio: added sys management v:110916\s.zaglio: used readpast v:110706\s.zaglio: special behaviour on systypes v:110629\s.zaglio: added list of triggers v:110628\s.zaglio: added db trigger script v:110623\s.zaglio: added call of sp__style v:110406\s.zaglio: added script of triggers v:110307.1000\s.zaglio: a small bug on single sp v:110220\s.zaglio: added system tables v:110213\s.zaglio: replaced readpast with nolock v:110102\s.zaglio: added obj info v:110121\s.zaglio: added nolock v:101107\s.zaglio: added show of structure of temp tables v:100919\s.zaglio: added show of ##var## and #var# v:100616\s.zaglio: removed help after attached v:100529\s.zaglio: added use of #dbg v:100528\s.zaglio: a bug near local srv, other db obj position v:100518\s.zaglio: added temp vars to not disturbe scope of caller v:100423\s.zaglio: manage #tbls v:100422\s.zaglio: a minor enh v:100418\s.zaglio: added synonym management v:100228\s.zaglio: help developers;set this into tools\options menuù and connecto to CTRL+F1 t:sp__info #test1_2#3 -- good t:sp__info ''sysobjects'' t:fn__str, sp__emails, tr__script_trace_db t:sp__info ''sp__info'' t:sp__info ''sp__server_ip'' */ CREATE proc [sp__info] @what sysname=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 declare @dbg bit select @dbg=0 declare @crlf nvarchar(2) select @crlf=crlf from dbo.fn__sym() -- cerate local temps create table #src(lno int identity, line nvarchar(4000)) create table #vars (id nvarchar(16),value sql_variant) if not object_id(''tempdb..#dbg'') is null begin if @what is null begin exec(''#dbg'') goto ret end exec sp_executesql N''exec @ret=#dbg @what'', N''@ret int out,@what sysname'', @ret=@ret out,@what=@what if @dbg=-1 exec sp__printf ''#dbg:%d'',@ret if @ret!=0 goto ret end if not object_id(''sp_info'') is null begin if @what is null begin exec(''sp_info'') goto ret end exec @ret=sp_executesql N''@ret=sp_info @what'', N''int @ret out,@what sysname'', @ret=@ret out,@what=@what if @dbg=-11 exec sp__printf ''sp_info:%d'',@ret if @ret!=0 goto ret end if @what is null goto help if @dbg=1 exec sp__printf ''--- analyze'' declare @obj sysname,@type sysname,@objs nvarchar(4000), @n int,@i int,@sql nvarchar(4000),@id int, @svr sysname,@db sysname,@sch sysname,@sobj sysname, @synonym bit,@ok bit select @ok=0 if left(@what,1)=''#'' and dbo.fn__str_count(@what,''#'')>=3 and right(@what,1)!=''#'' begin select @what=substring(replace(@what,''_'','' ''),2,4000) exec sp__style @what goto ret end if left(@what,2)=''##'' and right(@what,2)=''##'' begin if @dbg=1 exec sp__printf ''--- ##cfg'' -- ##smtp_server## select @sql=N''sp__config ''''''+substring(@what,3,len(@what)-4)+'''''''' exec(@sql) end else begin if left(@what,1)=''#'' and right(@what,1)=''#'' begin if @dbg=1 exec sp__printf ''--- #cfg'' select @sql=N''sp_config ''''''+substring(@what,2,len(@what)-2)+'''''''' exec(@sql) end end select @id=object_id(@what) if @id is null and dbo.fn__ismssql2k()=0 select @id=object_id,@type=[type] from sys.triggers where [name]=@what if @dbg=1 exec sp__printf ''@id=%d'',@id if @id is null and left(@what,1)=''#'' and right(@what,1)!=''#'' begin if @dbg=1 exec sp__printf ''--- direct id'' select @id=object_id(''tempdb..''+@what),@type=''u'' -- could be a #proc: todo select fld,def into #tmptbldef from fn__sql_def_cols(@what,default,default) exec sp__select_astext ''select fld,def from #tmptbldef with (nolock)'', @header=1 drop table #tmptbldef end select @objs=coalesce(@objs+''|'','''')+[name]+''(''+xtype+'')'',@type=xtype from sysobjects with (nolock) where [name] like replace(@what,''_'',''[_]'')+''%'' if dbo.fn__ismssql2k()=0 select @objs=coalesce(@objs+''|'','''')+[name]+''(''+[type]+'')'',@type=[type] from sys.triggers with (nolock) where [name] like replace(@what,''_'',''[_]'')+''%'' and parent_id=0 -- sp__info sp_ select @n=dbo.fn__str_count(@objs,''|'') if @n>1 and @id is null begin if @dbg=1 exec sp__printf ''--- multi find'' select @n=max(len(token))+1 from dbo.fn__str_table(@objs,''|'') select @sql=null declare @ll int select @ll=(132/@n*@n)+2 -- select * from dbo.fn__str_table(''a,b,c'','','') select @sql =coalesce(@sql,'''')+left(token+replicate('' '',@n),@n) +case when pos%(132/@n)=0 then @crlf else '' '' end from dbo.fn__str_table(@objs,''|'') print @sql print ''-------------------------------------------------------------------------'' -- exec sp__printf ''%s'',@sql end if not @id is null or @what like ''sys[0-9]%'' begin if @dbg=1 exec sp__printf ''type is %s'',@type if @type=''sn'' begin select @synonym=1 select -- lower(sy.type_desc),sc.name + ''.'' + sy.name as synonym_name,sy.base_object_name, @sql=sy.base_object_name, @svr=parsename(sy.base_object_name,4), @db=parsename(sy.base_object_name,3), @sch=parsename(sy.base_object_name,2), @sobj=parsename(sy.base_object_name,1) from sys.synonyms sy with (nolock) join sys.schemas sc with (nolock) on sc.schema_id = sy.schema_id where sy.[object_id] = @id exec sp__printf ''-- synonym: -> %s.%s.%s.%s'',@svr,@db,@sch,@sobj if @dbg=1 exec sp__printf ''%s sv:%s db:%s sc:%s ob:%s'',@sql,@svr,@db,@sch,@sobj select @sql=''use [%db%] select @type=xtype from sysobjects with (nolock) where id=object_id(''''[%sch%].[%obj%]'''')'' exec sp__str_replace @sql out,''%svr%|%db%|%sch%|%obj%'',@svr,@db,@sch,@sobj select @sql=replace(@sql,'''''''','''''''''''') if @svr is null select @sql=''exec [%db%]..sp_executesql N''''''+@sql+'''''',N''''@type sysname out'''',@type=@type out'', @what=quotename(@db)+''.''+quotename(@sch)+''.''+quotename(@sobj) else select @sql=''exec [%svr%].[%db%]..sp_executesql N''''''+@sql+'''''',N''''@type sysname out'''',@type=@type out'', @what=quotename(@svr)+''.''+quotename(@db)+''.''+quotename(@sch)+''.''+quotename(@sobj) exec sp__str_replace @sql out,''%svr%|%db%|%sch%|%obj%'',@svr,@db,@sch,@sobj select @type=null exec sp_executesql @sql,N''@type sysname out'',@type=@type out if @dbg=1 exec sp__printf ''@sql:%s @type:%s @what:%s'',@sql,@type,@what end -- fn_mc_and_wh if @what like ''sys[^0-9]%'' and not @what in (''systypes'',''sysobjects'',''syscolumns'',''syscomments'') select @what=''master..''+@what if @what like ''sys%'' select @sql=''select * from ''+@what+'' with (nolock)'' else select @sql=''select top 10 * from ''+@what+'' with (nolock)'' /* in the 110922, readpast caused in production the msg: Messaggio 650, livello 16, stato 1, riga 1 You can only specify the READPAST lock in the READ COMMITTED or REPEATABLE READ isolation levels. */ -- select xtype from sysobjects group by xtype if @type in (''p'',''fn'',''if'',''tf'',''tr'') begin if @dbg=1 exec sp__printf ''--script'' exec sp__script @what,@opt=''print'' select @ok=1 end if (@type in (''v'',''u'') and @id is null) or (@type is null and not @id is null) begin if @dbg=1 exec sp__printf ''-- show as text:\n%s'',@sql exec sp__select_astext @sql select @ok=1 end if @type in (''v'',''u'') and not @id is null begin if @dbg=1 exec sp__printf ''-- show data:\n%s'',@sql exec(@sql) select @sql=quotename(@svr)+''.''+quotename(@db)+''.dbo.sp__script ''''''+@sobj+'''''',@opt=''''reverse|print'''''' if @dbg=1 exec sp__printf ''%s'',@sql if @synonym=1 exec(@sql) if @dbg=1 exec sp__printf ''-- script'' else exec sp__script @what,@opt=''print'' -- table or view select @ok=1 end if @type is null and not @sql is null exec(@sql) end else -- not @id is null begin if @dbg=1 exec sp__printf ''--- single wild found'' if @objs is null -- try search with one char less select @objs=coalesce(@objs+''|'','''')+[name]+''(''+xtype+'')'',@type=xtype from sysobjects with (nolock) where [name] like replace(left(@what,len(@what)-1),''_'',''[_]'')+''%'' exec sp__printf ''%s'',@objs goto ret end if @ok=1 goto ret help: exec sp__usage @proc,'' Scope Help developers printing some info Notes I normally do this associations: ctrl+F1: sp__info ctrl+3: connection info (see below) ctrl+4: sp__dir @opt=''''*'''',@path= ctrl+5: (free) ctrl+6: sp__find ctrl+7: declare @db sysname;select @db=db_name();exec sp_script @db=@db,@obj= ctrl+8: sp__style ctrl+9: sp__script_debug ctrl+0: (free) Connection info (to put into single line before paste as shortcut): select @@servername svr,db_name() db,cn.connect_time,cn.client_net_address,cn.local_net_address from sys.dm_exec_connections cn where session_id=@@spid If exist into current db an SP_INFO, first are called this. If this return something !=0, stop execution otherwise continue showing info. Infos depends from parameter type: 1. proc/function/trigger show source 2. view/table select first 10 records 3. root of object if find one, reapply 1 & 2 3.1 if find more, print list 4. not 1,2,3 use sp__find @what 5. #... introduce a command 5.1 #svn#sp__info#s_zaglio call sp__svn... replace _ with . (TODO) 5.2 ##var## call sp__config ''''var'''' 5.3 #var# call SP_CONFIG ''''var'''' '' exec sp__printf ''Parameter:%s (!!!! keep in mind "__")'',@what select @ret=-1 goto ret ret: drop table #src drop table #vars return @ret end -- sp__info' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info: -- =============================================================== sp__info_code select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_code',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140115 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_code') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_code') with nowait goto skip_sp__info_code end if @ver>140115 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_code') with nowait goto skip_sp__info_code end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_code') with nowait if exists( select top 1 null from sys.objects where name='sp__info_code' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_code] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:code,statistics,lines,per,x,day,period v:140115\s.zaglio: added help v:090906\s.zaglio: do some statistics about code */ CREATE proc sp__info_code @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @eol nvarchar(4),@ln int, @app_dd money,@app_lns money,@utl_dd money,@utl_lns money, @app_n int,@utl_n int -- =========================================================== initialization == -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == select @eol=char(13),@ln=len(@eol) select @app_lns=sum((len(definition)-len(replace(definition,@eol,'''')))/@ln) from sys.sql_modules m where not object_name(object_id) like ''%[_][_]%'' select @utl_lns=sum((len(definition)-len(replace(definition,@eol,'''')))/@ln) from sys.sql_modules m where object_name(object_id) like ''%[_][_]%'' select @app_dd=sum(datediff(dd,create_date,modify_date)),@app_n=count(*) -- select top 1 * from sys.objects join sys.sql_modules on sys.objects.object_id=sys.sql_modules.object_id where not name like ''%[_][_]%'' and [type]!=''S'' select @utl_dd=sum(datediff(dd,create_date,modify_date)),@utl_n=count(*) -- select top 1 * from sys.objects join sys.sql_modules on sys.objects.object_id=sys.sql_modules.object_id where name like ''%[_][_]%'' and [type]!=''S'' select db_name() as db, @app_lns tot_app_lines,@app_dd tot_app_days, @app_lns/@app_dd app_lines_x_day,@app_n app_n_objs, cast(@app_lns/@app_n as int) app_lns_x_obj, @utl_lns tot_utl_lines,@utl_dd tot_utl_days, @utl_lns/@utl_dd utl_lines_x_day,@utl_n utl_n_objs, cast(@utl_lns/@utl_n as int) app_lns_x_obj, @utl_lns/@app_lns utl_lines_x_app -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope do some statistics about code (ecluding objects like table ofcourse) Notes applications objects info (sp,fn,views, ecc that NOT likes "%__%"): tot_app_lines total lines of code in the objects of application tot_app_days sum of days from creation to last modifications of objs app_lines_x_day average lines of code written per day app_n_objs total number of objects of the application app_lns_x_obj lines per object utilities objects info (sp,fn,views, ecc that likes "%__%"): tot_utl_lines tot_utl_days utl_lines_x_day utl_n_objs app_lns_x_obj utl_lines_x_app relation between utilites and application Parameters [param] [desc] @opt not used @dbg not used Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__info_code' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_code: -- ================================================================= sp__info_db select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_db',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130707 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_db') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_db') with nowait goto skip_sp__info_db end if @ver>130707 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_db') with nowait goto skip_sp__info_db end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_db') with nowait if exists( select top 1 null from sys.objects where name='sp__info_db' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_db] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility d:130630\s.zaglio: sp__maint_stats v:130707\s.zaglio: added multi pattern v:130630\s.zaglio: added rwstat option v:120910\s.zaglio: added density option v:120831\s.zaglio: added norm option v:120116\s.zaglio: added curr_idnt v:111216\s.zaglio: added index size in order v:100919.1005\s.zaglio: a remake t: select top 10 * into test from sysobjects exec sp__info_db ''test'' -- exec sp_spaceused ''ORDRSP_EDK14'' drop table test t:sp__info_db #,@dbg=1,@opt=''norm'' t:sp__info_db ''cf%|ts%'' */ CREATE proc [dbo].[sp__info_db] @objs nvarchar(512) = null, @opt sysname = null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 -- declarations declare @svr sysname,@db sysname,@sch sysname,@obj sysname, @qobj sysname,@id int, @sql nvarchar(max),@noout bit,@i int,@n int, @crlf varchar, @nodrop bit, @tbl_def nvarchar(4000) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''), @noout=1,@nodrop=0, @crlf=crlf from fn__sym() if @objs is null goto help if @objs=''#'' select @objs=''%'' select @svr=svr,@db=db,@sch=sch,@obj=obj -- select * from dbo.fn__parsename(@objs,0,1) if @svr!=dbo.fn__servername(null) goto err_lso create table #likes(pattern sysname) insert #likes select token from fn__str_table(@objs,''|'') if object_id(''tempdb..#objs'') is null create table #objs(id int identity,obj sysname) else select @nodrop=1 if object_id(''tempdb..#info_db'') is null begin create table #info_db ( id int identity, [name] sysname, [rows] int null, reserved sysname null, data sysname null, index_size sysname null, unused sysname null, max_row_len int null, data_n int null, index_size_n int null, unused_n int null, avg_bXrec real null, ncols smallint null, -- number of columns curr_idnt bigint null, -- last/max identity value norm bigint null, -- size of normalized data useeks bigint null, -- whole index user seeks uscans bigint null, -- whole index user scans ulckps bigint null, -- whole index user lookups ) end else select @noout=0 set @sql='' use [%db%] insert into #objs(obj) select o.name from sysobjects o join #likes l on o.name like l.pattern where xtype=''''u'''' '' exec sp__str_replace @sql out,''%db%|%obj%'',@db,@obj exec(@sql) drop table #likes select @i=min(id),@n=max(id) from #objs while (@i<=@n) begin select @obj=quotename(@db)+''.''+quotename(@sch)+''.''+quotename(obj) from #objs where id=@i insert #info_db([name],[rows],reserved,data,index_size,unused) exec sp_spaceused @obj select @i=@i+1 end -- while if @dbg=1 select [name], data, convert(int,dbo.fn__str_at(data,'''',1)) data_n, dbo.fn__str_at(data,'''',2) data_t, index_size, convert(int,dbo.fn__str_at(index_size,'''',1)) index_size_n, dbo.fn__str_at(data,'''',2) index_size , unused, convert(int,dbo.fn__str_at(unused,'''',1)) unused_n, dbo.fn__str_at(unused,'''',2) unused from #info_db order by [name] update #info_db set data_n =convert(int,dbo.fn__str_at(data,'''',1)), data =dbo.fn__str_at(data,'''',2), index_size_n=convert(int,dbo.fn__str_at(index_size,'''',1)), index_size =dbo.fn__str_at(data,'''',2), unused_n =convert(int,dbo.fn__str_at(unused,'''',1)), unused =dbo.fn__str_at(unused,'''',2), curr_idnt =ident_current([name]) update #info_db set avg_bXrec = (1.0*data_n*case data when ''kb'' then 1024 when ''mb'' then 1024*1024 else -1 end+ 1.0*index_size_n*case index_size when ''kb'' then 1024 when ''mb'' then 1024*1024 else -1 end- 1.0*unused_n*case unused when ''kb'' then 1024 when ''mb'' then 1024*1024 else -1 end ) / [rows] where [rows]>0 declare cs cursor local for select [name],object_id(name),quotename(name) from #info_db open cs while 1=1 begin fetch next from cs into @obj,@id,@qobj if @@fetch_status!=0 break select @sql='' update #info_db set ncols=( select count(*) from ''+quotename(@db)+''..syscolumns with (nolock) where id=''+convert(sysname,object_id(@obj))+'') where [name]=''''''+@obj+'''''' '' exec(@sql) if charindex(''|norm|'',@opt)>0 begin if @dbg>0 exec sp__printf ''-- collecting norm.info for %s'',@obj select @sql=null -- convert all in sql_variant to allow union select @sql = isnull(@sql+''union''+@crlf,'''') + ''select cast(''+quotename(c.name)+'' as sql_Variant) a '' + ''from ''+@qobj+'' with (nolock) '' + ''where not ''+quotename(c.name)+'' is null'' + @crlf from sys.columns c join sys.types t on c.user_type_id=t.user_type_id where object_id=@id -- select * from sys.types and not t.name in ( ''image'',''text'',''ntext'',''xml'', ''varbinary'',''binary'', ''varchar'',''nvarchar'', ''char'',''nchar'' ) and not t.max_length<8 -- sum lens (+8 meand id and ref id) select @sql = ''select '' + ''@n=sum(datalength(a)+8)/1024 '' + ''from (''+@crlf+@sql+'') tbl''+@crlf exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end -- add blob & binary data select @sql = @sql + ''select '' + ''@n=@n+sum(datalength(''+quotename(c.name)+'')+8) '' + ''from ''+@qobj+@crlf + ''where not ''+quotename(c.name)+'' is null'' + @crlf from sys.columns c join sys.types t on c.user_type_id=t.user_type_id where object_id=@id and t.name in (''image'',''text'',''ntext'',''xml'',''varbinary'',''binary'') exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end -- varchar(max) cannot converted as variant but simply distuinguisced select @sql=null select @sql = isnull(@sql+''union''+@crlf,'''') + ''select cast(''+quotename(c.name)+'' as nvarchar(max)) a '' + ''from ''+@qobj+'' with (nolock) '' + ''where not ''+quotename(c.name)+'' is null'' + @crlf from sys.columns c join sys.types t on c.user_type_id=t.user_type_id where object_id=@id and t.name in ( ''varchar'',''nvarchar'',''char'',''nchar'' ) -- sum lens select @sql = ''select '' + ''@n=@n+sum(datalength(a)+8)/1024 '' + ''from (''+@crlf+@sql+'') tbl''+@crlf exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end -- max_datalen<8 for data non normalizable select @sql=null select @sql = isnull(@sql+@crlf,'''') + ''select @n=@n+sum(datalength(''+quotename(c.name)+''))/1024 '' + ''from ''+@qobj+'' with (nolock) '' + ''where not ''+quotename(c.name)+'' is null'' + @crlf from sys.columns c join sys.types t on c.user_type_id=t.user_type_id where object_id=@id and t.max_length<8 exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end -- finally update tbl info exec(''update #info_db set norm=@n where name=''''''+@obj+'''''''') end -- norm if charindex(''|density|'',@opt)>0 begin -- sp__info_db #,@dbg=1,@opt=''density'' if @dbg>0 exec sp__printf ''-- collecting density info for %s'',@obj select @sql=null -- convert all in sql_variant to allow union select @sql = isnull(@sql+''+''+@crlf,'''') + ''(select count(*) '' + ''from ''+@qobj+'' with (nolock) '' + ''where ''+quotename(c.name)+'' is null)'' + @crlf -- select top 10 * from sys.columns c join sys.types t on c.user_type_id=t.user_type_id where object_id=@id and c.is_computed=0 select @sql=''select @n=''+@crlf+@sql select @n=0 exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end if @n>0 begin select @sql=''update #info_db set ''+ ''norm=100-((1.0*@n/(1.0*rows*ncols))*100.0) ''+ ''where name=''''''+@obj+'''''''' exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end end -- n>0 end -- density if charindex(''|rwstat|'',@opt)>0 begin -- sp__info_db ''#'',@opt=''rwstat'' select @sql='' update nfo set useeks=user_seeks,uscans=user_scans,ulckps=user_lookups from #info_db nfo join ( select object_name(ustat.object_id) as name, /* proportion_of_reads=case when sum(user_updates + user_seeks + user_scans + user_lookups) = 0 then null else cast(sum(user_seeks + user_scans + user_lookups) as decimal) / cast(sum(user_updates + user_seeks + user_scans + user_lookups) as decimal(19,2)) end, proportion_of_writes=case when sum(user_updates + user_seeks + user_scans + user_lookups) = 0 then null else cast(sum(user_updates) as decimal) / cast(sum(user_updates + user_seeks + user_scans + user_lookups) as decimal(19,2)) end, sum(user_seeks + user_scans + user_lookups) as total_reads sum(user_updates) as total_writes */ sum(user_seeks) as user_seeks, sum(user_scans) as user_scans, sum(user_lookups) as user_lookups from sys.dm_db_index_usage_stats as ustat join sys.indexes as i on ustat.object_id = i.object_id and ustat.index_id = i.index_id join sys.tables as t on t.object_id = ustat.object_id where i.type_desc in ( ''''clustered'''', ''''heap'''' ) group by ustat.object_id ) as idxs on nfo.name=idxs.name '' exec @ret=sp_executesql @sql,N''@n int out'',@n=@n out if @ret!=0 begin exec sp__printsql @sql goto err_cod end end -- rwstat end -- while of cursor close cs deallocate cs if @noout=1 begin select * from #info_db order by (data_n-unused_n+index_size_n) desc drop table #info_db end if @nodrop=0 drop table #objs goto ret -- =================================================================== errors == err_lso: exec @ret=sp__err ''local server only'',@proc goto ret err_cod: exec @ret=sp__err ''inside sql code'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope list info about space used by table objects Parameters @objs db, schema and object name to inspect obj can use wildchar like % and _ multiple group of objects can be separated by | (pipe) if @objs is #, means all tables of current db @opt options norm fill norm row with estime of normalized data(very slow) (work only on objects of local db) density fill norm row with % of rapport between not null values and n. of rows rwstat fill useeks, uscans, ulckps #info_db fill this table instead show results. create table #info_db ( id int identity, [name] sysname, [rows] int null, reserved sysname null, data sysname null, index_size sysname null, unused sysname null, max_row_len int null, data_n int null, index_size_n int null, unused_n int null, avg_bXrec real null, ncols smallint null, -- number of columns curr_idnt bigint null, -- last/max identity value norm bigint null, -- size of normalized data or density useeks bigint null, -- whole index user seeks uscans bigint null, -- whole index user scans ulckps bigint null -- whole index user lookups ) Notes If table #info_db is passed, data is returned and not shown Can be passed #objs to sub select tables create table #objs(id int identity,obj sysname) Examples exec sp__info_db ''''te%'''' '',@p1=@tbl_def select @ret=-1 ret: return @ret end -- sp__info_db' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_db: -- ================================================================= sp__info_io select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_io',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130707 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_io') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_io') with nowait goto skip_sp__info_io end if @ver>130707 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_io') with nowait goto skip_sp__info_io end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_io') with nowait if exists( select top 1 null from sys.objects where name='sp__info_io' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_io] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:disk,drives,files,virtual,db,performance,statistics,io v:130707\s.zaglio: give info about disk io c:from david wiseman (http://www.wisesoft.co.uk) */ CREATE proc sp__info_io @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- i/o stats by database select d.name as databasename, round(cast(sum(num_of_bytes_read+num_of_bytes_written) as float) / sum(sum(num_of_bytes_read+num_of_bytes_written)) over() *100,2) as [% total i/o], round(cast(sum(num_of_bytes_read) as float) / sum(sum(num_of_bytes_read)) over() *100,2) as [% read i/o], round(cast(sum(num_of_bytes_written) as float) / sum(sum(num_of_bytes_written)) over() *100,2) as [% write i/o], round(cast(sum(num_of_bytes_read+num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [total gb], round(cast(sum(num_of_bytes_read)/(1024*1024*1024.0) as float),2) as [read gb], round(cast(sum(num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [write gb], sum(io_stall) as [i/o total wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) -- i/o stall in days + cast(sum(io_stall) / 86400000 as varchar) -- length of max i/o stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall)/1000,0),114),8) as [i/o total wait time {days} hh:mm:ss], sum(io_stall_read_ms) as [i/o read wait ms] , isnull(nullif(right(replicate(''0'', -- length of max i/o read stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) -- i/o read stall in days + cast(sum(io_stall_read_ms) / 86400000 as varchar) -- length of max i/o read stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o read stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_read_ms)/1000,0),114),8) as [i/o read wait time {days} hh:mm:ss] , sum(io_stall_write_ms) as [i/o write wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o write stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) -- i/o write stall in days + cast(sum(io_stall_write_ms) / 86400000 as varchar) -- length of max i/o write stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o write stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_write_ms)/1000,0),114),8) as [i/o write wait time {days} hh:mm:ss], sum(io_stall) / nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o wait ms], sum(io_stall_read_ms) / nullif(sum(num_of_reads),0) as [avg read i/o wait ms], sum(io_stall_write_ms) / nullif(sum(num_of_writes),0) as [avg write i/o wait ms], sum(num_of_bytes_read+num_of_bytes_written)/nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o bytes], sum(num_of_bytes_read)/nullif(sum(num_of_reads),0) as [avg read i/o bytes], sum(num_of_bytes_written)/nullif(sum(num_of_writes),0) as [avg write i/o bytes], cast(max(sample_ms) / 86400000 as varchar) -- i/o write stall formatted to hh:mm:ss + '' '' + left(convert(varchar,dateadd(s,max(sample_ms)/1000,0),114),8) as [sample time {days} hh:mm:ss] from sys.dm_io_virtual_file_stats(null,null) vfs join sys.databases d on vfs.database_id = d.database_id group by d.name order by [% total i/o] desc; -- i/o stats by file select d.name as databasename, mf.name as logical_name, mf.physical_name, round(cast(sum(num_of_bytes_read+num_of_bytes_written) as float) / sum(sum(num_of_bytes_read+num_of_bytes_written)) over() *100,2) as [% total i/o], round(cast(sum(num_of_bytes_read) as float) / sum(sum(num_of_bytes_read)) over() *100,2) as [% read i/o], round(cast(sum(num_of_bytes_written) as float) / sum(sum(num_of_bytes_written)) over() *100,2) as [% write i/o], round(cast(sum(num_of_bytes_read+num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [total gb], round(cast(sum(num_of_bytes_read)/(1024*1024*1024.0) as float),2) as [read gb], round(cast(sum(num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [write gb], sum(io_stall) as [i/o total wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) -- i/o stall in days + cast(sum(io_stall) / 86400000 as varchar) -- length of max i/o stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall)/1000,0),114),8) as [i/o total wait time {days} hh:mm:ss], sum(io_stall_read_ms) as [i/o read wait ms] , isnull(nullif(right(replicate(''0'', -- length of max i/o read stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) -- i/o stall in days + cast(sum(io_stall_read_ms) / 86400000 as varchar) -- length of max i/o read stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o read stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_read_ms)/1000,0),114),8) as [i/o read wait time {days} hh:mm:ss] , sum(io_stall_write_ms) as [i/o write wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o write stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) -- i/o write stall in days + cast(sum(io_stall_write_ms) / 86400000 as varchar) -- length of max i/o write stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o write stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_write_ms)/1000,0),114),8) as [i/o write wait time {days} hh:mm:ss], sum(io_stall) / nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o wait ms], sum(io_stall_read_ms) / nullif(sum(num_of_reads),0) as [avg read i/o wait ms], sum(io_stall_write_ms) / nullif(sum(num_of_writes),0) as [avg write i/o wait ms], sum(num_of_bytes_read+num_of_bytes_written)/nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o bytes], sum(num_of_bytes_read)/nullif(sum(num_of_reads),0) as [avg read i/o bytes], sum(num_of_bytes_written)/nullif(sum(num_of_writes),0) as [avg write i/o bytes], cast(max(sample_ms) / 86400000 as varchar) -- i/o write stall formatted to hh:mm:ss + '' '' + left(convert(varchar,dateadd(s,max(sample_ms)/1000,0),114),8) as [sample time {days} hh:mm:ss] from sys.dm_io_virtual_file_stats(null,null) vfs join sys.databases d on vfs.database_id = d.database_id join sys.master_files mf on vfs.file_id = mf.file_id and mf.database_id = vfs.database_id group by d.name,mf.name,mf.physical_name order by [% total i/o] desc; -- i/o stats by drive select left(mf.physical_name,3) as drive, round(cast(sum(num_of_bytes_read+num_of_bytes_written) as float) / sum(sum(num_of_bytes_read+num_of_bytes_written)) over() *100,2) as [% total i/o], round(cast(sum(num_of_bytes_read) as float) / sum(sum(num_of_bytes_read)) over() *100,2) as [% read i/o], round(cast(sum(num_of_bytes_written) as float) / sum(sum(num_of_bytes_written)) over() *100,2) as [% write i/o], round(cast(sum(num_of_bytes_read+num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [total gb], round(cast(sum(num_of_bytes_read)/(1024*1024*1024.0) as float),2) as [read gb], round(cast(sum(num_of_bytes_written)/(1024*1024*1024.0) as float),2) as [write gb], sum(io_stall) as [i/o total wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) -- i/o stall in days + cast(sum(io_stall) / 86400000 as varchar) -- length of max i/o stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall)/1000,0),114),8) as [i/o total wait time {days} hh:mm:ss], sum(io_stall_read_ms) as [i/o read wait ms] , isnull(nullif(right(replicate(''0'', -- length of max i/o read stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) -- i/o stall in days + cast(sum(io_stall_read_ms) / 86400000 as varchar) -- length of max i/o read stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_read_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o read stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_read_ms)/1000,0),114),8) as [i/o read wait time {days} hh:mm:ss] , sum(io_stall_write_ms) as [i/o write wait ms], isnull(nullif(right(replicate(''0'', -- length of max i/o write stall in days over resultset (for dynamic padding - replicate) len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) -- i/o write stall in days + cast(sum(io_stall_write_ms) / 86400000 as varchar) -- length of max i/o write stall in days over resultset (for dynamic padding - right) ,len(isnull(cast(nullif(max(sum(io_stall_write_ms)) over() /86400000,0) as varchar),''''))) + '' '','' ''),'''') -- i/o write stall formatted to hh:mm:ss + left(convert(varchar,dateadd(s,sum(io_stall_write_ms)/1000,0),114),8) as [i/o write wait time {days} hh:mm:ss], sum(io_stall) / nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o wait ms], sum(io_stall_read_ms) / nullif(sum(num_of_reads),0) as [avg read i/o wait ms], sum(io_stall_write_ms) / nullif(sum(num_of_writes),0) as [avg write i/o wait ms], sum(num_of_bytes_read+num_of_bytes_written)/nullif(sum(num_of_reads+num_of_writes),0) as [avg i/o bytes], sum(num_of_bytes_read)/nullif(sum(num_of_reads),0) as [avg read i/o bytes], sum(num_of_bytes_written)/nullif(sum(num_of_writes),0) as [avg write i/o bytes], cast(max(sample_ms) / 86400000 as varchar) -- i/o write stall formatted to hh:mm:ss + '' '' + left(convert(varchar,dateadd(s,max(sample_ms)/1000,0),114),8) as [sample time {days} hh:mm:ss] from sys.dm_io_virtual_file_stats(null,null) vfs join sys.databases d on vfs.database_id = d.database_id join sys.master_files mf on vfs.file_id = mf.file_id and mf.database_id = vfs.database_id group by left(mf.physical_name,3) order by [% total i/o] desc; -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope returns io statistics by: database,file,drive Parameters [param] [desc] @opt options @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__info_io' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_io: -- ============================================================= sp__info_server select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_server',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130517 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_server') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_server') with nowait goto skip_sp__info_server end if @ver>130517 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_server') with nowait goto skip_sp__info_server end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_server') with nowait if exists( select top 1 null from sys.objects where name='sp__info_server' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_server] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:server,instance,port,ip,address v:130517\s.zaglio: get info about server */ CREATE proc sp__info_server @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common -- @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), -- @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) -- |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == select * into #tmp from fn__server_info() exec sp__select_asform ''#tmp'',@opt=''noh|dot'' drop table #tmp -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope [write here a short desc] Parameters [param] [desc] @opt options @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__info_server' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_server: -- ================================================================ sp__info_svr select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_svr',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130107 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_svr') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_svr') with nowait goto skip_sp__info_svr end if @ver>130107 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_svr') with nowait goto skip_sp__info_svr end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_svr') with nowait if exists( select top 1 null from sys.objects where name='sp__info_svr' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_svr] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:virtual,file,log,vlf,enterprise,size,db,dbs,server,status v:130107\s.zaglio: get global info about entire server todo:integrate sp__util_vlf t:sp__info_svr detail */ CREATE proc sp__info_svr @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options @sel bit,@print bit,@detail bit, @end_declare bit -- =========================================================== initialization == select @detail=charindex(''|detail|'',@opt), @sel=charindex(''|sel|'',@opt), @print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- if @run=0 goto help -- =============================================================== #tbls init == create table #dbs( srv sysname, db sysname, lname sysname, pname nvarchar(1024), size int, um nvarchar(4), density float null, unusedvlf int null, usedvlf int null, totalvlf int null ) -- ===================================================================== body == if @detail=1 insert #dbs(srv,db,lname,pname,size,um) select @@servername, db_name(database_id) as db, name as logical_name, physical_name, (size*8)/1024 size, ''MB'' um from sys.master_files insert #dbs(srv,db,lname,pname,size,um) select @@servername,''*'',''*'',''*'', case when cast(sum(sizemb)/(1024.0*1024.0) as int)=0 then cast(sum(sizemb)/1024.0 as int) else cast(sum(sizemb)/(1024.0*1024.0) as int) end as size, case when cast(sum(sizemb)/(1024.0*1024.0) as int)=0 then ''GB'' else ''TB'' end as size_um from ( select db_name(database_id) as databasename, name as logical_name, physical_name, (size*8)/1024 sizemb from sys.master_files ) sizes if @sel=1 select * from #dbs else begin exec sp__select_astext ''select * from #dbs'' -- separate from help exec sp__prints ''8<'' end -- ================================================================== dispose == dispose: drop table #dbs goto help -- ===================================================================== help == help: exec sp__usage @proc,'' Scope get global info about entire server Notes lname is logical name pname is physical name Parameters @opt options detail show detail about all databases, not only the sum '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__info_svr' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_svr: -- ================================================================ sp__info_tbl select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__info_tbl',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130426 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__info_tbl') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__info_tbl') with nowait goto skip_sp__info_tbl end if @ver>130426 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__info_tbl') with nowait goto skip_sp__info_tbl end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__info_tbl') with nowait if exists( select top 1 null from sys.objects where name='sp__info_tbl' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__info_tbl] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:130426\s.zaglio: short comment t:sp__info_tbl rep05_delivery_notes t:sp__info_tbl rep06_delivery_notes_details,@dbg=1 t:sp__info_tbl rep07_files,@dbg=1 */ CREATE proc sp__info_tbl @tbl sysname = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, @i int,@n bigint, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @col sysname, @len int, @typ sysname, @sql nvarchar(max), @oid int, @rows bigint, @d datetime,@ms int, @rf real, -- reference factor @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), -- @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) -- |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @oid=object_id(@tbl), @end_declare=1 declare @cols table( id smallint identity primary key, tbl sysname, col sysname, typ sysname, ln int, n_distinct bigint, pctw tinyint, -- whole effective occupation pctt tinyint, -- text fields effective occupation ms int, idxs tinyint, -- num of indexes where present ok_col bit default(1) ) -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @tbl is null goto help if @oid is null raiserror(''table not found'',16,1) -- =============================================================== #tbls init == -- ===================================================================== body == -- count all records select @rows=dbo.fn__count(@tbl) insert @cols(tbl,col,typ,ln,n_distinct) select @tbl,''*'',''*'',0,@rows insert @cols(tbl,col,typ,ln,n_distinct) select @tbl,c.name,t.name,c.length,0 from syscolumns c join systypes t on c.xusertype=t.xusertype where id=@oid and iscomputed=0 order by colorder update @cols set ok_col=0 where typ in (''*'',''image'') -- calculate rf -- rf is a factor used to predict more correctly what happen if we change the -- colum value with a int reference -- (4*n.of.cols)/sum(size(n.of.cols))*100 select @rf=4.0*(select count(*) from @cols where ok_col=1 and ln>=4) /(select sum(ln) from @cols where ok_col=1 and ln>=4) if @dbg>0 exec sp__printf ''--rf:%d'',@rf declare cs cursor local for select col from @cols where ok_col=1 open cs while 1=1 begin fetch next from cs into @col if @@fetch_status!=0 break if @dbg>0 exec sp__printf ''-- scanning col:%s'',@col select @sql=null,@d=getdate() select @sql=''select @n=count(*) '' +''from (select distinct [''+@col+''] from [''+@tbl+'']) a'' exec sp_executesql @sql,N''@n bigint out'',@n=@n out exec sp__elapsed @d out,@ms=@ms out update @cols set n_distinct=@n, pctw=cast((1.0*@n)/(@rows*1.0)*100 as int), ms=@ms where col=@col end -- cursor cs close cs deallocate cs update @cols set pctw=(select sum(pctw)/count(*) from @cols where ok_col=1), pctt=( select sum(pctw)/count(*) from @cols where ok_col=1 and (typ like ''%char%'' or typ like ''%text%'') ), ms=(select avg(ms) from @cols where ok_col=1) where col=''*'' -- correct with rf update @cols set pctw=pctw+pctw*@rf,pctt=pctt+pctt*@rf update c set idxs=i.n from @cols c join ( select columnname col,count(*) n from fn__script_idx(@oid) group by columnname ) i on c.col=i.col -- t:sp__info_tbl log_ddl,@dbg=1 if not object_id(''tempdb..#sp__info_tbl_results'') is null insert #info_tbl(tbl,col,typ,ln,n_distinct,pctw,pctt,ms,idxs) select tbl,col,typ,ln,n_distinct,pctw,pctt,ms,idxs from @cols else begin select tbl,col,typ,ln,n_distinct,pctw,pctt,ms,idxs into #info_tbl from @cols exec sp__select_astext ''select * from #info_tbl order by typ'' drop table #info_tbl end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope estime the redundancy of data of a table Note will be excluded computed and image columns How read results pctw is the percentage of whole data effectively used pctt is the percentage of only text data but effectively used ms is the time required to distinct data; in the row * is the average of all rows and can be used to estime the access time per rows where calculate the pctw to predict how we can gain after a normalization/aggregation NB1: the redundancy is vertical and do not consider couple; so a waste of a single column can be normal if is coupled with an other; for example the bill address can redundant alone but correct if coupled with the ship address NB2: the pct above 100% are normals because is considered an index called referential index that predict the replacement of a value with its index; so if pctw/pctt will be above than 100, normally mean that the table is already normalized Parameters @tbl table name @opt options #info_tbl if present fill this table instead of print values create table #info_tbl( tbl sysname, col sysname, -- * is about all columns of table typ sysname, ln int, n_distinct bigint, pctw tinyint, -- whole effective occupation pctt tinyint, -- text fields effective occupation ms int, idxs tinyint -- num of indexes where present ) Examples sp__info_tbl log_ddl '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__info_tbl' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__info_tbl: -- ================================================================== sp__insert select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__insert',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090703 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__insert') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__insert') with nowait goto skip_sp__insert end if @ver>090703 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__insert') with nowait goto skip_sp__insert end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__insert') with nowait if exists( select top 1 null from sys.objects where name='sp__insert' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__insert] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:090703\S.Zaglio: added transaction r:090626\S.Zaglio: used fn__flds_quotename r:090205\S.Zaglio: added header management r:090129\S.Zaglio: corrected management of '' in data r:081218\S.Zaglio: added random delete and reinsert or a single row and @rows r:081021\S.Zaglio: insert constant data or from a select or table t:sp__insert ''test'',''v1|v2|v3\v4|v5|v6'',@row_sep=''\'',@dbg=1 select * from test t:sp__insert ''ot04_stock'',@excludes=''sync_dt'',@random=1,@dbg=1 -- delete and reinsert a random line t: ALTER table test(a int, b sysname, c sysname,d int, e sysname) declare @test nvarchar(4000) set @test=''19|BATCH|OT03_BATCH_NUMBER|2|(null) 20|BATCH|OT05_BATCH_DETAILS|3|(null) 21|BATCH|OT06_BATCH_DOCS|4|(null) 22|BATCH|A23_BATCH_DOCS|1|(null) '' exec sp__insert ''test'',@test,@null=''(null)'',@dbg=1 select * from test drop table test */ CREATE proc [dbo].[sp__insert] @into sysname=null, @from nvarchar(4000)=null, -- values,table,select @flds nvarchar(4000)=null, -- fields name @rows bigint=null out, @excludes nvarchar(4000)=null, @col_sep nvarchar(8)=''|'', @row_sep nvarchar(8)=null, @header bit=0, @random bit=0, @null nvarchar(16)=null, @trans bit=1 , @dbg bit=0 as begin set nocount on declare @crlf nvarchar(2) set @crlf=char(13)+char(10) if @into is null begin exec sp__usage ''sp__insert'' goto ret end if @row_sep is null set @row_sep=@crlf declare @i int, @col int ,@cols int declare @sql nvarchar(4000) declare @values nvarchar(4000) declare @where nvarchar(4000) declare @table sysname declare @row nvarchar(4000) declare @value sysname declare @consts bit set @consts=0 declare @s sysname declare @err int if @random=1 begin if @flds is null and @header=0 set @flds=dbo.fn__flds_of(@into,'','',@excludes) set @table=@into if @where is null set @where=dbo.fn__flds_of(@table,'','',@excludes) set @sql=''SELECT top 1 ''+@where+'' FROM ''+@table+'' ORDER BY newid() desc'' -- get a random line set @values='''' exec sp__select @sql,@body=@values out,@null=''(/null/)'',@dtstyle=126 set @values=dbo.fn__inject(@values) set @where=replace(@where,'','','' and '') set @where=dbo.fn__str_exp(dbo.fn__str_exp(''%%=''''@@'''''',@where,'' and ''),@values,''|'') set @where=replace(@where,''=''''(/null/)'''''','' is null '') set @sql=''DELETE FROM ''+@table+'' WHERE ''+@where if @dbg=1 exec sp__printf @sql exec(@sql) set @rows=@@rowcount if @rows!=1 begin print ''no deleted row'' goto err end set @values=dbo.fn__str_exp(''''''%%'''''',@values,''|'') set @values=replace(@values,''|'','','') set @sql=''insert into %tbl%(%flds%)\n values(%values%)'' exec sp__str_replace @sql out,''\n|%tbl%|%flds%|%values%|''''(/null/)'''''',@crlf,@table,@flds,@values,''null'' if @dbg=1 exec sp__printf @sql exec(@sql) set @rows=@@rowcount if @rows!=1 begin print ''no inserted row'' goto err end goto ret end if charindex(@col_sep,@from)>0 or charindex(@row_sep,@from)>0 set @consts=1 if @consts=1 begin set @rows=dbo.fn__str_count(@from,@row_sep) set @cols=dbo.fn__str_count(@from,@col_sep) end set @i=1 -- populate flds statement if @header=1 begin set @flds=replace(dbo.fn__str_at(@from,@row_sep,@i),@col_sep,'','') set @i=@i+1 end if @flds is null begin set @flds=dbo.fn__flds_of(@into,'','',null) end -- prepare fields names set @flds=dbo.fn__flds_quotename(@flds,'','') if @trans=1 begin if @dbg=1 exec sp__printf ''begin transaction'' begin transaction end set @null=''''''''+@null+'''''''' while (@i<=@rows) begin set @row=dbo.fn__str_at(@from,@row_sep,@i) set @row=replace(@row,'''''''','''''''''''') set @i=@i+1 if @row='''' continue /* if dbo.fn__exists(@into,''U'')=0 begin set @sql=''select into @tbl select '' set @col=1 set @values='''' while (@col<@cols) begin set @s=str(@col) set @value=dbo.fn__str_at(@row,@col_sep,@col) if isdate(@value)=1 set @value=''getdate() as col''+@s else if isnumeric(@value)=1 set @value=str(@value)+'' as col''+@s else set @value=''''''''+replicate(''-'',255)+'''''' as col''+@s if @values<>'''' set @values=@values+'','' set @values=@values+@value end -- while */ set @values=''''''%%'''''' set @values=dbo.fn__str_exp(@values,@row,@col_sep) set @values=replace(@values,@col_sep,'','') set @values=replace(@values,@null,''null'') set @sql=''insert into @tbl(@flds) values(@from) set @err=@@error'' /* if @consts=1 begin set @values=dbo.fn__str_exp(''''''%%'''''',@from,@col_sep) set @values=replace(@values,@col_sep,'','') set @from=''values(''+@values+'')'' end */ exec sp__str_replace @sql out,''@tbl|@flds|@from'',@into,@flds,@values if @dbg=1 exec sp__printf @sql exec sp_executesql @sql,N''@err int out'',@err=@err out if @err!=0 goto err end -- while if @trans=1 begin if @dbg=1 exec sp__printf ''commit transaction'' commit transaction end goto ret err: if @trans=1 begin if @dbg=1 exec sp__printf ''rollback transaction'' rollback end ret: end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__insert: -- ====================================================================== sp__io select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__io',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120515 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__io') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__io') with nowait goto skip_sp__io end if @ver>120515 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__io') with nowait goto skip_sp__io end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__io') with nowait if exists( select top 1 null from sys.objects where name='sp__io' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__io] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,io v:120515\s.zaglio: total revision v:120514\s.zaglio: support I/O between files and application */ CREATE proc sp__io @cod nvarchar(4000) = null, @id int = null out, @opt sysname = null, @dbg int = 0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @cod is null goto help -- ============================================================== declaration == declare @end_declare bit -- =========================================================== initialization == select @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == -- drop table iof drop view iof_list if object_id(''iof'') is null begin create table iof( tid tinyint, id int identity(-2147483648,1) constraint pk_iof primary key, rid int not null, -- parent pid int null, flags smallint not null, wrong as cast(iof.flags & dbo.fn__flags(''F'') as bit), processed as cast(iof.flags & dbo.fn__flags(''G'') as bit), idx int null, -- line number txt nvarchar(4000) not null,-- file/path/... name or line of text dt datetime null -- date of file ) create index ix_iof_rid on iof(rid,id) end -- io_files -- tids select @id=null select @id=id from tids,iof where iof.tid=tids.grp and txt=@cod if @@rowcount=0 begin -- truncate table iof -- sp__io null,''test'' begin tran insert iof(tid,rid,flags,txt) select tids.grp,0,0,@cod from tids select @id=@@identity update iof set rid=@id where id=@id commit end goto ret -- =================================================================== errors == err_nid: exec @ret=sp__err ''code for tid must be specified'',@proc goto ret err_trn: exec @ret=sp__err ''inside transaction'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope support I/O between files and application If not exists, create/alter table "iof" and other structures. See flags.iof.* for other specifics. Parameters @id out id of record @cod name of group @opt options (not used) Examples -- insert a new grp record and/or return the id is already exists -- if necessary, creare/update structures exec sp__io @id=@gid out,@cod=''''my group'''' -- store a text file -- header insert iof(tid,rid,flags,txt) select tids.[file],@gid,0,''''filename.ext'''' from tids select @fid=@@identity -- rows insert iof(tid,rid,flags,idx,txt) select tids.code,@fid,0,txt.lno,txt.line from tids,#src as txt order by txt.lno -- list files of my group select txt from tids,iof where iof.tid=tids.file and iof.rid=@gid '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__io' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__io: -- ===================================================================== sp__job select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131126 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job') with nowait goto skip_sp__job end if @ver>131126 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job') with nowait goto skip_sp__job end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job') with nowait if exists( select top 1 null from sys.objects where name='sp__job' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,utijob v:131126\s.zaglio: near run not working v:121108\s.zaglio: better err_nosp and restyle v:121010\s.zaglio: added collate database_default v:121004\s.zaglio: noew correctly check emails separated by ; or , or | v:120613\s.zaglio: captured out of sp_update_job; and tests, see comments v:111130\s.zaglio: added @ref v:111118.1832\s.zaglio: expanded @job to multiple and added proc info and off option v:111110\s.zaglio: added output to #jobs v:110720.1638\s.zaglio: some imprecision in help, added warning v:110706\s.zaglio: added once schedule v:110610\s.zaglio: done and tested each case whoen in help r:110609\s.zaglio: reviewed @at parse r:110607\s.zaglio: reviewed @at parse v:110318\s.zaglio: added quiet v:110305\s.zaglio: a small bug near ena/dis job v:110212\s.zaglio: added macro %db% v:110130\s.zaglio: used sp_update_job to enable/disable jobs v:110119\s.zaglio: added DIS option to disable v:101222\s.zaglio: added multi schedule v:101221\s.zaglio: added multi schedule v:101204\s.zaglio: added log,dis,ena in @opt v:100919.1320\s.zaglio: better name for steps of sql statements and steps flow v:100919.1305\s.zaglio: added delete of log files and adapted to new version of sp__job_status v:100919.1225\s.zaglio: a bug in job of single step v:100919.1210\s.zaglio: added slot management v:100919\s.zaglio: a bug near job with same sp of diff. db v:100912\s.zaglio: added last run date/time v:100724.1100\s.zaglio: a remake t:msdb..sp_help_job -- msdb.dbo.sp_get_composite_job_info */ CREATE proc [dbo].[sp__job] @job sysname = null, @sp nvarchar(4000) = null, @at sysname = null, @emails nvarchar(1024) = null, @smtp sysname = null, @ref sysname = null, @opt sysname = null, @dbg int =0 as begin set nocount on declare @proc sysname,@ret int, @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid),@ret=0 select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @dbg=1 exec sp__printf ''-- scope: %s'',@proc -- 120613\s.zaglio: rarely do not disable without errors if @@trancount>0 goto err_trn /* -- drop table #xp_results create table #xp_results( [job id] uniqueidentifier not null, [last run date] int not null, [last run time] int not null, next_run_date int not null, next_run_time int not null, next_run_schedule_id int not null, requested_to_run int not null, -- bool request_source int not null, request_source_id sysname collate database_default null, running int not null, -- bool current_step int not null, current_retry_attempt int not null, job_state int not null ) insert #xp_results exec msdb..xp_sqlagent_enum_jobs @is_sysadmin = 1, @job_owner = '''' */ select @job=replace(@job,''%db%'',db_name()) select @job=replace(@job,''*'',''#'') select @job=replace(@job,''#'',''%'') if charindex(''%'',@job)>0 select @job=replace(replace(@job,''_'',''[_]''),'''''''','''''''''''') select @sp =replace(@sp ,''*'',''#'') if @job is null or (@job!=''%'' -- 120613\s.zaglio: a bug on list and charindex(''%'',@job)>0 and @sp is null ) goto help select @emails=ltrim(rtrim(isnull(@emails,''''))), @smtp=ltrim(rtrim(isnull(@smtp,''''))) if @emails!='''' and @smtp='''' select @smtp=ltrim(rtrim(convert(sysname,dbo.fn__config(''smtp_server'',null)))) if @emails!='''' and @smtp='''' goto err_logv if @job=''%'' and @sp=''#'' goto err_cdaj if @emails!='''' and not dbo.fn__chk_email(@emails,'';,|'') is null goto err_wrem -- ============================================================== declaration == if @dbg=-1 exec sp__printf ''== declaration =='' declare @cmd_log nvarchar(4000),@n int, @jid uniqueidentifier,@sid int,@lid int,@schid int, @db sysname,@i int,@dt datetime, @freq_type int,@freq_interval int, @freq_subday_type int, @freq_subday_interval int,@freq_relative_interval int, @freq_recurrence_factor int, @start_date int, @end_date int, @start_time int, @end_time int,@at_msg sysname, @time int,@date int, @crlf nvarchar(2),@cmd nvarchar(4000),@step sysname, @ofa int,@osa int,@id int, @sql nvarchar(4000), @log nvarchar(512) declare @cod table(cod char(3),val tinyint,typ tinyint) insert @cod /* -- month select ''jan'',1 union select ''feb'',2 union select ''mar'',3 union select ''apr'',4 union select ''may'',5 union select ''jun'',6 union select ''jul'',7 union select ''aug'',8 union select ''sep'',9 union select ''oct'',10 union select ''nov'',11 union select ''dec'',12 union */ -- week day -- print ascii(''D'') select ''sun'',1 ,68 union select ''mon'',2 ,68 union select ''tue'',4 ,68 union select ''wed'',8 ,68 union select ''thu'',16 ,68 union select ''fri'',32 ,68 union select ''sat'',64 ,68 union -- special day -- print ascii(''S'') select ''eom'',1 ,83 union -- end of month select ''fom'',2 ,83 -- 1st of month declare -- select * from msdb..sysschedules @ranges table( id int identity primary key, token varchar(64), pos int, [start_date] int null, [end_date] int null, [start_time] int null default(0), [end_time] int null default (235959), interval int null default (0), freq_type int null default (0), freq_subday_type int null default (0), freq_interval int null default (0), freq_subday_interval int null default (0), freq_relative_interval int null default (0), freq_recurrence_factor int null default (0) ) -- @ranges -- ============================================================== init ===== if @dbg=-1 exec sp__printf ''== init =='' select @crlf=crlf from fn__sym() select @i=charindex(''|log:'',@opt) if @i>0 select @log=substring(@opt,@i+5,charindex(''|'',@opt,@i+5)-@i-5) if @log=''%temp%'' select @log=null if charindex(''|sql|'',@opt)>0 select @db=db_name(), @cmd=@sp, @step=dbo.fn__hex(dbo.fn__crc32(@cmd)) else begin if @sp!=''#'' begin if @dbg=1 exec sp__printf ''checking if exists sp "%s"'',@sp if object_id(@sp) is null goto err_nosp end select @db=isnull(parsename(@sp,3),db_name()), @cmd=parsename(@sp,1), -- become name of step @step=replace(replace(@db+''.''+@cmd,''.'',''_''),'' '',''_'') end -- search fors single job select @n=count(*) from msdb..sysjobs j where j.name like @job -- there is/are no jobs to delete if @n=0 and @sp=''#'' goto ret if @dbg=1 exec sp__printf ''found %d jobs'',@n if @n=1 select @job=[name],@jid=job_id from msdb..sysjobs j where j.name like @job if charindex(''|ena|'',@opt)>0 and not @jid is null and @sp is null begin /* this dont work...i don''t know why update msdb.dbo.sysjobs set enabled = 1 where job_id=@jid */ exec @ret=msdb.dbo.sp_update_job @job_id=@jid,@enabled=1 -- 120613\s.zaglio: rarely do not disable without errors if 1!=(select enabled from msdb.dbo.sysjobs where job_id=@jid) or @ret!=0 goto err_upj goto ret end if charindex(''|dis|'',@opt)>0 and not @jid is null and @sp is null begin /* this dont work because sqlagent keep info in memory update msdb.dbo.sysjobs set enabled = 0 where job_id=@jid */ exec @ret=msdb.dbo.sp_update_job @job_id=@jid,@enabled=0 -- 120613\s.zaglio: rarely do not disable without errors if 0!=(select enabled from msdb.dbo.sysjobs where job_id=@jid) or @ret!=0 goto err_upj goto ret end select @sid=step_id from msdb..sysjobsteps s where s.job_id=@jid and [step_name]=@step -- search if already exist a previous log step select @lid=step_id,@cmd_log=command from msdb..sysjobsteps s where s.job_id=@jid and [step_name]=@proc+''_status'' if not @emails is null begin if ''##'' in (left(@smtp,2),right(@smtp,2)) begin select @smtp=convert(sysname,dbo.fn__config(substring(@smtp,3,len(@smtp)-4),null)) end else begin if ''#'' in (left(@smtp,1),right(@smtp,1)) begin select @sql=N''select @smtp=convert(sysname,dbo.fn_config('''''' +substring(@smtp,2,len(@smtp)-2)+'''''',null)'' exec sp_executesql @sql,N''@smtp sysname out'',@smtp=@smtp out end end if @smtp is null goto err_smtp select @cmd_log=''sp__job_status @mins=-1,@jobs=''''''+@job+'''''''' +'',@to=''''''+@emails+''''''''+coalesce('',@smtp=''''''+@smtp+'''''''','''') +isnull('',@ref=''''''+@ref+'''''''','''') +'',@opt='''''' if charindex(''|sp4|'',@opt)>0 select @cmd_log=@cmd_log+''sp4'' if charindex(''|sp8|'',@opt)>0 select @cmd_log=@cmd_log+''|sp8'' select @cmd_log=@cmd_log+'''''''' end else begin if @dbg>0 exec sp__printf ''Warning! Without @emails, the status step is omitted.'' end -- ================================================================ list jobs == if @dbg=-1 exec sp__printf ''== list jobs =='' if charindex(''%'',@job)>0 and @sp is null begin select @cmd_log='' select date_modified,[name],[enabled],date_created,version_number from msdb..sysjobs j with (nolock) where j.name like ''''''+@job+'''''' order by 1 desc,2 desc '' exec sp__select_astext @cmd_log goto ret end -- list of jobs -- ======================================================== list steps of job == if @dbg=-1 exec sp__printf ''== list steps =='' if not @jid is null and @sp is null and @emails is null and @at is null and charindex(''|run|'',@opt)=0 begin -- sysjobactivity,sysjobhistory,sysjobs,sysjobschedules -- sysjobservers,sysjobsteps,sysjobs_view,sysjobstepslogs >=mssql2k8 select @cmd_log='' select s.step_id id, s.step_name, case when len(s.command)>40 then left(s.command,40)+''''...'''' else s.command end as command, s.last_run_date,s.last_run_time, case s.last_run_outcome when 0 then ''''not completed'''' when 1 then ''''completed'''' when 2 then ''''new try'''' when 3 then ''''aborted'''' when 5 then ''''unknown'''' end las_run_outcome, s.database_name,s.output_file_name from msdb..sysjobsteps s with (nolock) where s.job_id=''''{1}'''' order by 1'' exec sp__select_astext @cmd_log,@p1=@jid goto ret end -- list steps of job -- ================================================== at parameter management == if @dbg=-1 exec sp__printf ''== at parameter manag =='' -- ########################## -- ## -- ## parse schedule -- ## -- ######################################################## -- tech info at: http://msdn.microsoft.com/it-it/library/ms366342.aspx if not @at is null begin if @dbg=2 exec sp__printf ''calculating schedule...'' declare @tkn sysname,@tk1 sysname,@tk2 sysname,@tk3 sysname declare @ats table (pos int,tkn sysname,typ tinyint) insert @ats(pos,tkn,typ) select pos,token, case when left(token,1)=''+'' then 0 -- n minutes from now when patindex(''%[:;]%'',token)=0 and charindex(''-'',token)>0 then 90 -- start date when patindex(''%[;-]%'',token)=0 and charindex('':'',token)>0 then 80 -- time when patindex(''%[:;-]%'',token)=0 and (right(token,1) in (''w'',''d'',''h'',''n'') or token in (select cod from @cod)) then 1 -- occurrencies when patindex(''%[:;-]%'',token)>0 then 5 -- ranges when token=''once'' -- one time then 99 end from dbo.fn__str_table(@at,'''') -- adjust times & dates update @ats set tkn=convert(int,dbo.fn__str_at(tkn,'':'',1)*10000) +convert(int,dbo.fn__str_at(tkn,'':'',2)*100) +convert(int,isnull(dbo.fn__str_at(tkn,'':'',3),0)) where typ=80 update @ats set tkn=convert(int,dbo.fn__str_at(tkn,''-'',1)*10000) +convert(int,dbo.fn__str_at(tkn,''-'',2)*100) +convert(int,dbo.fn__str_at(tkn,''-'',3)) where typ=90 -- test how many they are if (select count(*) from @ats where typ=80)>2 or (select count(*) from @ats where typ=90)>2 goto err_tmdt -- set 80,90 to 1st and 81,91 to second if (select count(*) from @ats where typ=80)=2 update @ats set typ=81 where typ=80 and tkn= (select max(cast(tkn as int)) from @ats where typ=80) if (select count(*) from @ats where typ=90)=2 update @ats set typ=91 where typ=90 and tkn= (select max(cast(tkn as int)) from @ats where typ=90) if @dbg=2 select * from @ats select @i=min(pos),@n=max(pos) from @ats select @freq_type=8, -- the base is week @freq_interval=null, -- if null, all days @freq_subday_type=null, @freq_subday_interval=0,@freq_relative_interval=0, @freq_recurrence_factor=null, @at_msg='''', @start_date=convert(int,convert(sysname,getdate(),112)), @end_date=99991231 if exists(select top 1 null from @ats where typ=1) -- one range for all occurrencies insert @ranges(token,[start_date],start_time,end_time,end_date) select ''*'',@start_date,0,235959,@end_date -- scan schedule commands declare cs cursor local for select tkn,typ from @ats order by typ open cs while 1=1 begin fetch next from cs into @tkn,@i if @@fetch_status!=0 break if @i=0 -- NN minutes from now insert @ranges(token,start_time,freq_type,freq_interval,freq_subday_type) select @at, convert ( int, replace( convert( sysname, dateadd( s,convert(int,substring(@at,2,10)), getdate()), 8), '':'','''') ), freq_time=1, freq_interval=0, freq_subday_type=1 -- time range (hh:mm:ss-hh:mm:ss;step) if @i=5 begin select @tk3=dbo.fn__str_at(@tkn,'';'',2), -- step @tk2=dbo.fn__str_at(@tkn,'';'',1), -- end @tk1=dbo.fn__str_at(@tk2,''-'',1), -- start @tk2=dbo.fn__str_at(@tk2,''-'',2) -- exec sp__printf ''tk1:%s, tk2:%s, tk3:%s'',@tk1,@tk2,@tk3 if @tk3='''' goto err_range if left(@tk3,1) like ''[1-9]'' and right(@tk3,1) in (''h'',''n'') insert @ranges( token,interval,start_time,end_time,freq_type, freq_subday_type,freq_subday_interval, freq_interval) select @tkn, interval =convert(int,left(@tk3,len(@tk3)-1)), start_time =convert(int,dbo.fn__str_at(@tk1,'':'',1)*10000) +convert(int,dbo.fn__str_at(@tk1,'':'',2)*100) +convert(int,isnull(dbo.fn__str_at(@tk1,'':'',3),0)), end_time =convert(int,dbo.fn__str_at(@tk2,'':'',1)*10000) +convert(int,dbo.fn__str_at(@tk2,'':'',2)*100) +convert(int,isnull(dbo.fn__str_at(@tk2,'':'',3),0)), freq_type =case right(@tk3,1) when ''h'' then 4 when ''n'' then 4 end, freq_subday_type=case right(@tk3,1) when ''h'' then 8 when ''n'' then 4 end, freq_subday_interval=left(@tk3,len(@tk3)-1), freq_interval=1 else goto err_range end -- time range if @i=1 -- occurrencies begin -- exec sp__job ''spj_test'',@at=''48w mon 10:30'',@dbg=2 -- exec sp__job ''spj_test'',@at=''1w Tue Wed 10:30'',@dbg=2 -- exec sp__job ''spj_test'',@at=''1w Tue Wed'',@dbg=2 -- select * from msdb..sysschedules select @tk1=right(@tkn,1),@tk2=substring(@tkn,1,len(@tkn)-1) if @tkn in (select cod from @cod where typ=68) select @freq_interval=@freq_interval|val from @cod where cod=@tkn and typ=68 if @tkn=''fom'' select @freq_type=32,@freq_interval=8,@freq_relative_interval=1, @freq_subday_type=1 if @tkn=''eom'' select @freq_type=32,@freq_interval=8,@freq_relative_interval=16, @freq_subday_type=1 if @tk1=''w'' and isnumeric(@tk2)=1 select @freq_recurrence_factor=@tk2,@freq_subday_type=1 -- specific hour if @tk1=''h'' and isnumeric(@tk2)=1 select @freq_subday_type=8,@freq_subday_interval=@tk2 if @tk1=''n'' and isnumeric(@tk2)=1 select @freq_subday_type=4,@freq_subday_interval=@tk2 update @ranges set freq_type=@freq_type, freq_interval=isnull(@freq_interval,1|2|4|8|16|32|64), freq_subday_type=@freq_subday_type, freq_subday_interval=@freq_subday_interval, freq_relative_interval=@freq_relative_interval, freq_recurrence_factor=@freq_recurrence_factor where token=''*'' end -- occurrencies -- set stard/end date/time if @i in (90,91,80,81) -- if not exist at least one schedule... and not exists(select null from @ranges) insert @ranges(token,[start_date],start_time,end_time,end_date, freq_type,freq_interval) select ''*'',@start_date,0,235959,@end_date, 4,1 if @i=90 update @ranges set [start_date]=@tkn if @i=91 update @ranges set [end_date]=@tkn if @i=80 update @ranges set [start_time]=@tkn if @i=81 update @ranges set [end_time]=@tkn if @i=99 update @ranges set freq_type=1 end -- while of cursor for ats close cs deallocate cs -- some last common adjustements update @ranges set freq_recurrence_factor=isnull(freq_recurrence_factor,1), freq_subday_Type=isnull(freq_subday_Type,1) if @dbg=2 select * from @ranges -- verify declare @schedule_description nvarchar(255) declare cs cursor local for select [start_date],end_date,start_time,end_time, freq_type,freq_subday_type,freq_interval, freq_subday_interval,freq_relative_interval, freq_recurrence_factor from @ranges open cs while 1=1 begin fetch next from cs into @start_date,@end_date,@start_time,@end_time, @freq_type,@freq_subday_type,@freq_interval, @freq_subday_interval,@freq_relative_interval, @freq_recurrence_factor if @@fetch_status!=0 break select @schedule_description ='''' exec msdb..sp_get_schedule_description @freq_type=@freq_type, @freq_interval=@freq_interval, @freq_subday_type=@freq_subday_type, @freq_subday_interval=@freq_subday_interval, @freq_relative_interval=@freq_relative_interval, @freq_recurrence_factor=@freq_recurrence_factor, @active_start_date=@start_date, @active_end_date=@end_date, @active_start_time=@start_time, @active_end_time=@end_time, @schedule_description=@schedule_description out if @schedule_description is null or @dbg=2 begin exec sp__printf '' description = %s freq_type = %d freq_interval = %d freq_subday_type = %d freq_subday_interval = %d active_start_date = %d active_start_time = %d active_end_date = %d active_end_time = %d freq_recurrence_fac = %d'' ,@schedule_description, @freq_type, @freq_interval, @freq_subday_type, @freq_subday_interval, @start_date, @start_time, @end_date, @end_time, @freq_recurrence_factor exec sp__printf '' freq_relative_interval = %d'',@freq_relative_interval if @schedule_description is null begin exec sp__printf ''!! warning: null schedule description !!'' select @at_msg=isnull(@at_msg,''generic'') end end -- dbg end -- while of cursor close cs deallocate cs if @at_msg!='''' goto err_csch end -- @at -- ====================================================== begin job managment == if @dbg=-1 exec sp__printf ''== begin job man =='' begin tran if @sp=''#'' begin -- delete msg must be visible from user exec sp__printf ''deleting job/s(%s)...'',@job -- delete job while (1=1) begin select @jid=null select top 1 @jid=job_id from msdb..sysjobs j where j.name like @job if @jid is null break exec sp__printf '' deleting job/s(%s)...'',@jid -- step into steps and delete log files if exists declare cs cursor local for select output_file_name from msdb..sysjobsteps s where job_id=@jid and not output_file_name is null open cs while 1=1 begin fetch next from cs into @log if @@fetch_status!=0 break exec sp__printf '' deleting log (%s)...'',@log select @cmd=''del /q "''+@log+''"'' exec master..xp_cmdshell @cmd,no_output end -- while of cursor close cs deallocate cs exec @ret=msdb..sp_delete_job @job_id=@jid if @@error!=0 or @ret!=0 goto err_jdel end -- while if @sp=''#'' goto ret select @jid=null,@sid=null,@lid=null end -- no error if delete a job that not exists (but no msg is outed) if @jid is null and @sp=''#'' goto ret if @jid is null and @sp is null and @at is null and @emails is null goto err_njob -- if @sp is null and @sid is null and @sp is null -- and not @at is null -- change at -- ============================================================= change email == if @dbg=-1 exec sp__printf ''== chg email =='' if charindex(''|run|'',@opt)=0 and @sp is null and @sid is null and not @emails is null begin if @jid is null goto err_njob if @dbg=1 exec sp__printf ''updating emails...'' exec msdb..sp_update_jobstep @job_id=@jid,@step_id=@lid, @command=@cmd_log end -- chg email -- ====================================================== create update steps == if @dbg=-1 exec sp__printf ''== create upd steps =='' if not @sp is null begin -- create job if not exists or drop if exists same step name if @jid is null begin if @dbg=1 exec sp__printf ''add new job "%s" on server "(local)"'',@job exec msdb..sp_add_job @job_name = @job, @job_id=@jid out exec msdb..sp_add_jobserver @job_id=@jid, @server_name=''(local)'' end if @jid is null goto err_njob -- ============================================================ log file name == if @dbg=-1 exec sp__printf ''== log file name =='' if charindex(''|nolog|'',@opt)=0 begin if @log is null exec sp__get_temp_dir @log out if right(@log,1)!=''\'' select @log=@log+''\'' select @log=@log+@step+''_log.txt'' end if not @lid is null begin if @dbg=1 exec sp__printf ''deleting log step (%d)...'',@lid exec @ret=msdb..sp_delete_jobstep @job_id=@jid,@step_id=@lid if @@error!=0 or @ret!=0 goto ret end -- ================================================================= add step == if @dbg=-1 exec sp__printf ''== add step =='' if charindex(''|elapsed|'',@opt)>0 select @cmd =''declare @d datetime,@ms int''+@crlf +''exec sp__elapsed @d out''+@crlf +''exec ''+quotename(@sp)+@crlf +''exec sp__elapsed @d,@ms=@ms out''+@crlf +''exec sp__log ''''''+@sp+'''''',@n=@ms'' if @sid is null begin if @dbg=1 exec sp__printf ''add step "%s" on db "%s"...'',@step,@db exec @ret=msdb..sp_add_jobstep @job_id = @jid, @step_name = @step, -- @step_id = @lid, -- insert before last @subsystem = ''tsql'', @command = @cmd, @database_name=@db, @on_success_action=1, -- for single job of single step @on_fail_action=2, @output_file_name=@log, @flags=0 -- overwrite log --@retry_attempts = 5, --@retry_interval = 5 end else begin if @dbg=1 exec sp__printf ''update step "%s"...'',@step exec @ret=msdb..sp_update_jobstep @job_id = @jid, @step_id = @sid, -- replace @subsystem = ''tsql'', @command = @cmd, @database_name=@db, @on_success_action=3, -- next step @on_fail_action=3, @output_file_name=@log, @flags=0 -- overwrite log --@retry_attempts = 5, --@retry_interval = 5 end if @@error!=0 or @ret!=0 goto err_step -- ========================================================= re-add log error == if @dbg=-1 exec sp__printf ''== re-add log =='' select @lid=null if not @cmd_log is null begin exec @ret=msdb..sp_add_jobstep @job_id = @jid, @step_name = ''sp__job_status'', @subsystem = ''tsql'', @command = @cmd_log, @database_name=@db if @@error!=0 or @ret!=0 goto err_logs -- adjust non log steps select @lid=null select @lid=step_id from msdb..sysjobsteps s where s.job_id=@jid and [step_name]=''sp__job_status'' if @dbg=1 exec sp__printf ''-- added log step with step id=%d'',@lid end -- log /* examples step if_ok if_err if_err_ras if_nolog 1 next log next end 2 next log next end 3 next/end log next end log end end end - */ if @dbg=1 exec sp__printf ''-- align gotos of steps'' select @i=1,@id=max(step_id) from msdb..sysjobsteps s where s.job_id=@jid select @osa=3 -- next if charindex(''|ras|'',@opt)>0 select @ofa=3 -- next else select @ofa=case when @lid is null then 2 else 4 end -- goto while (@i<=@id) begin if @i=@id select @osa=1,@ofa=2 if @dbg=1 exec sp__printf ''-- step_id @i=%d, @osa=%d, @ofa=%d, @lid=%d (1=end ok;2=end ko;3=next;4=goto)'',@i,@osa,@ofa,@lid exec @ret=msdb..sp_update_jobstep @job_id=@jid,@step_id=@i, @on_success_action =@osa, @on_fail_action =@ofa, @on_fail_step_id =@lid select @i=@i+1 end -- while -- if @dbg=1 select * from msdb..sysjobsteps where job_id=@jid end -- add/chg steps -- ================================================== run/add/change schedule == if @dbg=-1 exec sp__printf ''== add/change schedule =='' if charindex(''|dis|'',@opt)>0 begin exec sp__printf ''disabling job %s'',@jid exec @ret=msdb.dbo.sp_update_job @job_id=@jid,@enabled=0 -- 120613\s.zaglio: rarely do not disable without errors if 0!=(select enabled from msdb.dbo.sysjobs where job_id=@jid) or @ret!=0 goto err_upj end -- ########################## -- ## -- ## set schedule -- ## -- ######################################################## if not @at is null begin if @jid is null goto err_njob declare cs cursor local for select [name] -- select * from msdb..sysjobschedules j1 -- prob not compatible with mssql2k join msdb..sysschedules j2 on j1.schedule_id=j2.schedule_id where job_id=@jid open cs while 1=1 begin fetch next from cs into @tkn if @@fetch_status!=0 break if @dbg=1 exec sp__printf ''deleting schedule (%s) for update'',@tkn exec @ret=msdb..sp_delete_jobschedule @job_id=@jid,@name=@tkn end -- delete schedules close cs deallocate cs -- readd schedules declare cs cursor local for select id,start_date,end_date,start_time,end_time, freq_type,freq_subday_type,freq_interval, freq_subday_interval,freq_relative_interval, freq_recurrence_factor from @ranges open cs while 1=1 begin fetch next from cs into @schid,@start_date,@end_date,@start_time,@end_time, @freq_type,@freq_subday_type,@freq_interval, @freq_subday_interval,@freq_relative_interval, @freq_recurrence_factor if @@fetch_status!=0 break select @tkn=@job+''(''+convert(sysname,@schid)+'')'' if @dbg=1 exec sp__printf ''adding schedule "%s"'',@tkn exec @ret=msdb..sp_add_jobschedule @name = @tkn, @job_id = @jid, @enabled = 1, @freq_type = @freq_type, @freq_interval = @freq_interval, @freq_subday_type = @freq_subday_type, @freq_subday_interval = @freq_subday_interval, @freq_relative_interval = @freq_relative_interval, @freq_recurrence_factor = @freq_recurrence_factor, @active_start_time = @start_time, @active_start_date = @start_date, @active_end_time = @end_time, @active_end_date = @end_date end -- while add schedule close cs deallocate cs end -- schedule goto ret -- =================================================================== errors == err:exec @ret=sp__err @e_msg,@proc,@p1=@e_p1 goto ret err_njob:select @e_msg=''no job found or created'' goto err err_aani:select @e_msg=''at changes not implemented again'' goto err err_eani:select @e_msg=''email changes not implemented again'' goto err err_nsql:select @e_msg=''SQL option not implemented again'' goto err err_nosp:select @e_msg=''stored proc. %s not found'',@e_p1=@sp goto err err_step:select @e_msg=''creating step'' goto err err_logs:select @e_msg=''creating log step'' goto err err_wrem:select @e_msg=''wrong email (%s)'',@e_p1=@emails goto err err_csch:select @e_msg=''calculating schedule:%s'',@e_p1=@at_msg goto err err_jdel:select @e_msg=''deleting jobs'' goto err err_cdaj:select @e_msg=''cannot delete all jobs'' goto err err_smtp:select @e_msg=''smtp server not specified'' goto err err_logv:select @e_msg=''smtp or emails empty'' goto err err_range:select @e_msg=''missing or wrong step in range'' goto err err_tmdt:select @e_msg=''too mach times or dates'' goto err err_trn:select @e_msg=''this sp cannot be executed into a transaction'' goto err err_upj: /* not necessary because hope that sp_update_job shown its errors exec @ret=sp__err ''sp_update_job failed'',@proc */ goto ret -- ===================================================================== help == help: -- month jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec (only one) exec sp__usage @proc,'' Scope create and maintain jobs with log and error management Parameters #jobs optional table where store running jobs @job is the name of job to manage; accept # as wild char and multiple roots separated by pipe ("|") @sp is the name of stored that the step call (if already exists, will be replaced with new info) if is "#", the job will be deleted @at time of execution (see below) @email emails wich send the log in case of failure of job Use "ras" to run all steps before send the lists of failed @ref is a generic text passed directly to sp__job_status @opt options @dbg 2 show a more detailed schedule description Options ras continue to next step if current fail log:path alternative path for output file (by default a %temp%\@db@proc_log.txt file is created) nolog do not output to file elapsed enable tracing of executions with sp__log sql consider @sp as a generic sql run start the job immediatelly quiet do not show msg about run of job (succesfull...errors..etc) sp4 send one email every 4h even if the jub fail every 5 minutes sp8 send one email every 8h dis disable the job (also immediatelly, see exampe) ena enabled the job (also immediatelly, see exampe) off print scripts to disable and re-enable active jobs Time expressions yyyy-mm-dd start date hh:nn:ss every day at hh:nn if start date unspecified ??w every ?? weeks ??h every ?? hours ??n every ?? minutes day Mon Tue Wed Thu Fri Sat Sun (multiple option) +NNNNN start after NN seconds hh:mm-hh:mm;step interval; step can be every ?h, ?m, ?d, ?n (see above) fom 1st of month eom end of month once execute only one time Optional output table for running jobs (returned by master..xp_sqlagent_enum_jobs) create table #jobs( id int identity, [server] sysname, [name] sysname, [description] nvarchar(512), job_id uniqueidentifier, last_run_date int, last_run_time int, -- process info spid int null, [from] nvarchar(32) null, [sql] nvarchar(256) null ) Examples: -- help and list of running jobs sp__job -- list of jobs sp__job # -- or ''''*'''' -- list of job by root sp__job myj# -- add 1st step (and create the job) and the second sp__job ''''my job'''',''''sp_test'''' sp__job ''''my job'''',''''sp_test1'''' -- list steps sp__job ''''my job'''' -- delete job sp__job ''''my_job'''',# -- add sql step sp__job ''''my_job'''',''''sp__log #my_job'''',@opt=''''sql'''' -- add/chg error control and email to wich send log sp__job ''''my_job'''',@email=''''fname.lname@mails.org'''' -- add/chg schedule sp__job ''''my_job'''',@at=''''10:30'''' -- every day at 10:30 sp__job ''''my_job'''',@at=''''10:30-20:30;5h'''' -- start at 10:30 end at 20:30 every 5 hours -- multi time sp__job ''''my_job'''',@at=''''00:00-08:00;2h 08:00-21:00;20n 21:00-23:59;2h'''' sp__job ''''my_job'''',@at=''''Tue'''' -- every Tuesday at midnight sp__job ''''my_job'''',@at=''''Sat Sun 10:30'''' -- every weekend at 10:30 sp__job ''''my_job'''',@at=''''Sat Sun 8:00 21:00 20n'''' -- vertical range sp__job ''''my_job'''',@at=''''5n'''' -- every five minutes from midnight sp__job ''''my_job'''',@at=''''48w mon 10:30'''' -- every 1st monday in december -- at 10:30 sp__job ''''my_job'''',@at=''''fom 10:30'''' -- every 1st of month at 10:30 sp__job ''''my_job'''',@at=''''eom 10:30'''' -- every end of month at 10:30 sp__job ''''my_job'''',@at=''''+5'''' -- start 5 minutes from now sp__job ''''my_job'''',@at=''''2011-07-14 20:20'''' -- start the 14 jul, every day at 20:20 sp__job ''''my_job'''',@at=''''2011-07-14 20:20 once'''' -- start the 14 jul, only one time at 20:20 -- delete a job sp__job ''''my_job'''',# -- delete my jobs sp__job ''''my#'''',# -- disable a job sp__job ''''my job'''',@opt=''''dis'''' -- print script to turn off and on active jobs (excluding disabled) sp__job ''''myjobs1#|myjobs2#'''',@opt=''''off'''' '' -- list running -- declare @cmd_log nvarchar(4000),@name sysname,@n int,@ret int if object_id(''tempdb..#jobs'') is null create table #jobs( id int identity, [server] sysname, [name] sysname, [description] nvarchar(512), job_id uniqueidentifier, last_run_date int, last_run_time int, -- process info spid int null, [from] nvarchar(32) null, [sql] nvarchar(256) null ) declare @filter table(job sysname) insert @filter select token from fn__str_table(@job,''|'') select @sql=replace('' select * into #xp_results -- select * from openrowset( "sqloledb", "server=''+@@servername+'';trusted_connection=yes", "set fmtonly off exec msdb..xp_sqlagent_enum_jobs @is_sysadmin = 1, @job_owner = """" ")'', ''"'', '''''''') select @sql=@sql+'' insert #jobs( [server], [name], [description], job_id, last_run_date, last_run_time ) '' -- select top 1 * from msdb..sysjobs if dbo.fn__isMSSQL2K()=1 select @sql=@sql+'' select top 100 percent j.originating_server, j.name, j.description, j.job_id, r.[last run date] as start_date, r.[last run time] as start_time from #xp_results r join msdb..sysjobs j with (nolock) on r.[job id]=j.job_id where r.running = 1 order by 1,2'' else select @sql=@sql+'' select top 100 percent s.srvname originating_server, j.name running_job_name, j.description, j.job_id, r.[last run date] as start_date, r.[last run time] as start_time from #xp_results r join msdb..sysjobs j on r.[job id]=j.job_id join master..sysservers s with (nolock) on s.srvid=j.originating_server_id where r.running = 1 order by 1,2'' if @dbg=1 exec sp__printsql @sql exec(@sql) if @@error!=0 exec sp__printsql @sql if not @job is null delete from #jobs where not id in ( select id from #jobs j join @filter f on j.[name] like f.job ) update #jobs set spid=procs.spid, [from]=procs.batch_duration, [sql]=left(procs.sql,256) from #jobs join ( select p.spid , right(convert(varchar, dateadd(ms, datediff(ms, p.last_batch, getdate()), ''1900-01-01''), 121), 12) as ''batch_duration'' , case when p.program_name like ''sqlagent - tsql jobstep (job %'' then ( select top 1 j.name from msdb..sysjobs j where rtrim(ltrim(dbo.fn__str_between(p.program_name,''job '','' :'',default))) = dbo.fn__hex(convert(varbinary,job_id)) ) else object_name((select top 1 objectid from ::fn_get_sql(p.sql_handle))) end as obj , case when p.program_name like ''sqlagent - tsql jobstep (job %'' then ( select top 1 j.job_id from msdb..sysjobs j where rtrim(ltrim(dbo.fn__str_between(p.program_name,''job '','' :'',default))) = dbo.fn__hex(convert(varbinary,job_id)) ) else null end as job_id , p.hostname , p.loginame , substring((select top 1 text from ::fn_get_sql(p.sql_handle)), coalesce(nullif(case p.stmt_start when 0 then 0 else p.stmt_start / 2 end, 0), 1), case (case p.stmt_end when -1 then -1 else p.stmt_end / 2 end) when -1 then datalength((select top 1 text from ::fn_get_sql(p.sql_handle))) else ((case p.stmt_end when -1 then -1 else p.stmt_end / 2 end) - (case p.stmt_start when 0 then 0 else p.stmt_start / 2 end) ) end ) as [sql] from master.dbo.sysprocesses p where p.spid!=@@spid and p.spid > 50 and p.status not in (''background'', ''sleeping'') and p.cmd not in (''awaiting command'' ,''mirror handler'' ,''lazy writer'' ,''checkpoint sleep'' ,''ra manager'') and p.sql_handle!=0x0 -- order by batch_duration desc ) procs on procs.job_id=#jobs.job_id select * from #jobs order by id if charindex(''|off|'',@opt)>0 select ''update msdb..sysjobs set [enabled]=''+switch+'' where job_id=''''''+ convert(varchar(64),j.job_id)+'''''' -- ''+j.[name]+'' (''+[description]+'')'' from (select ''0'' switch union select ''1'' switch) switches, ( select j.* from msdb..sysjobs j join @filter f on j.[name] collate database_default like f.job collate database_default where [enabled]=1 ) j order by switch,j.name set @ret=-1 goto ret -- ===================================================================== exit == ret: if @@trancount>0 if @ret=0 commit else rollback if @ret=0 and charindex(''|run|'',@opt)>0 begin if charindex(''|quiet|'',@opt)=0 exec msdb..sp_start_job @job_id = @jid else -- unfortunatelly is not possible manage error 22022 -- even if the running job are checked exec msdb..sp_start_job @job_id = @jid, @output_flag =0 end -- run return @ret end -- sp__job #' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job: -- ============================================================= sp__job_monitor select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job_monitor',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=101116 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job_monitor') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job_monitor') with nowait goto skip_sp__job_monitor end if @ver>101116 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job_monitor') with nowait goto skip_sp__job_monitor end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job_monitor') with nowait if exists( select top 1 null from sys.objects where name='sp__job_monitor' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job_monitor] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,utijob v:101116\s.zaglio: a bug near fn_config/fn__config sql v:100929.1000\s.zaglio: install a job monitor for other monitor t:exec sp__job_monitor ''stezagl@tin.it'',''lupin'' */ CREATE proc sp__job_monitor @to nvarchar(1024) = null, @smtp nvarchar(1024) = null, @jobs nvarchar(1024) = null, @excludes nvarchar(1024) = null, @h int = null, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard api: 0=ok -1=help, any=error id select @proc=''sp__job_monitor'', @ret=0 if @to is null or @smtp is null goto help -- declarations declare @at sysname,@sp nvarchar(4000),@mins int, @jname sysname,@sql nvarchar(4000) -- initialization if left(@smtp,2)=''##'' and right(@smtp,2)=''##'' begin select @sql=''select @smtp=convert(sysname,dbo.fn__config('''''' +substring(@smtp,3,len(@smtp)-4)+'''''',null))'' if @dbg=1 exec sp__printf ''-- %s'',@sql exec sp_executesql @sql,''@smtp sysname out'',@smtp=@smtp out end else begin if left(@smtp,1)=''#'' and right(@smtp,1)=''#'' begin select @sql=''select @smtp=convert(sysname,dbo.fn_config('''''' +substring(@smtp,2,len(@smtp)-2)+'''''',null))'' if @dbg=1 exec sp__printf ''-- %s'',@sql exec sp_executesql @sql,''@smtp sysname out'',@smtp=@smtp out end end select @jname=''process montor ''+dbo.fn__hex(dbo.fn__crc32(@to)), @h=isnull(@h,2), @at=convert(sysname,@h)+''h'', @mins=@h*60, @sp=''exec sp__job_status @mins=''+convert(sysname,@mins)+ '',@jobs=''''''+coalesce(@jobs,''%'')+''''''''+ coalesce('',@excludes=''''''+@excludes+'''''''','''')+ '',@to=''''''+@to+''''''''+ '',@body=''''report jobs of:''+@@servername+''''''''+ '',@smtp=''''''+@smtp+'''''''' -- ===================================================================== body == if @dbg=1 exec sp__printf ''sp:%s'',@sp exec sp__job @jname, @sp=@sp, @at=@at, @opt=''sql'' goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' scope install a job that monitor other processes parameters @to email;email;email which send list of failures @smtp smtp server; a special syntax can be used here: ##var_name## read value using "fn__config(''''var_name'''',null)" #var_name# read value using "fn_config(''''var_name'''',null)" @jobs by default monitor all jobs but can specify xxx|yyy|... to monitor all jobs that start with xxx or yyy @excludes to excludes jobs that start with xxx or yyy @h by default is every 2 hours, the slot time to monitor notes the process monitor will have name "process monitor xxx" where xxx is a crc code of @emails. examples exec sp__job_monitor ''''stezagl@tin.it'''',''''lupin'''' exec sp__job_monitor ''''stefano.zaglio@seltris.it'''',''''lupin'''' exec sp__job ''''process monitor#'''',# -- delete all monitors '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__job_monitor' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job_monitor: -- =============================================================== sp__job_setup select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job_setup',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110305 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job_setup') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job_setup') with nowait goto skip_sp__job_setup end if @ver>110305 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job_setup') with nowait goto skip_sp__job_setup end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job_setup') with nowait if exists( select top 1 null from sys.objects where name='sp__job_setup' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job_setup] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,utijob v:110305\s.zaglio:populate DB jobs from a local app table t:sp__job_setup @dbg=1 t:sp__job_setup ''%'',@opt=''dis'',@dbg=1 t:sp__job_setup ''%'',@tt=''%db_name%|db1|a|utility|u|db3|c'',@dbg=1 t:sp__job_setup ''%'',@opt=''run|dis'',@dbg=1 */ CREATE proc sp__job_setup @like sysname=null, @root sysname=null, @tt nvarchar(4000)=null, @opt sysname=null, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard API: 0=OK -1=HELP, any=error id declare @tbl sysname select @proc=object_name(@@procid), @ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''), @tbl=convert(sysname,dbo.fn__config(''jobs_setup_table'',''tbl_jobs_setup'')) -- ========================================================= param formal chk == if (@like is null and @opt=''||'') or object_id(@tbl) is null goto help -- ============================================================== declaration == declare @emails sysname,@smtp sysname,@at sysname,@sql nvarchar(4000), @ttv sysname,@i int,@job sysname,@sp sysname,@db sysname, @run bit,@crlf nvarchar(2) declare @ttt table(tkn sysname,val sysname) -- =========================================================== initialization == select top 1 @run=charindex(''|run|'',@opt), @i=charindex(''|'',@tt),@db=db_name(), @emails=convert(nvarchar(4000),dbo.fn__config(''job_setup_emails'',null)), @smtp=convert(sysname,dbo.fn__config(''job_setup_smtp'', dbo.fn__config(''smtp_server'',null))), @crlf=crlf from dbo.fn__sym() -- sp__config ''job%'', sp__config ''job_setup_emails'','''',''see sp__job_setup'' -- sp__config ''job_setup_emails'',@del=1 if dbo.fn__chk_email(@emails,default)=0 goto err_email select @ttv=left(@tt,@i-1) select @ttv=replace(@ttv,''%db_name%'',@db) select @ttv=convert(sysname,dbo.fn__config(@ttv,@ttv)) insert @ttt select vt.token,vs.token from (select * from dbo.fn__str_table(substring(@tt,@i+1,4000),''|'') vt where vt.pos%2=1) vt join (select vs.pos-1 pos,token from dbo.fn__str_table(substring(@tt,@i+1,4000),''|'') vs where vs.pos%2=0) vs on vt.pos=vs.pos if @dbg=1 begin select * from @ttt exec sp__printf ''-- @ttv=%s, @i=%s'',@ttv,@i end select @ttv=val from @ttt where tkn=@ttv if @dbg=1 exec sp__printf ''-- @ttv=%s'',@ttv -- ======================================================== second params chk == -- ===================================================================== body == -- initialization create table #jobs( id int, rif sysname, -- 3 chars for person job sysname, -- @root+... rs sysname, -- filter system in multi system env. sp sysname, -- stored proc name sched sysname, -- HH:MM or HHs:MMs Nm HHe:MMe opt sysname null, email sysname null, ) exec(''insert into #jobs select * from [''+@tbl+'']'') if @@error!=0 goto err_tbl update #jobs set opt=dbo.fn__str_quote(isnull(opt,''''),''|'') if charindex(''|dis|'',@opt)>0 update #jobs set opt=opt+''dis|'' if @dbg=1 select * from #jobs -- ===================================================================== body == select s.id, isnull(@root+''_'','''')+job as job, isnull( replace( sp, ''%ttv%'', isnull((select tkn from @ttt where val=@ttv),@db) ) -- replace ,sp -- is null ) sp, sched, dbo.fn__str_quote(opt,''|'') opt into #steps from #jobs s where dbo.fn__str_in(@ttv,s.rs,'''')=1 and (@like is null or job like @like) update steps set sp=@db+''.dbo.''+sp from #steps steps where charindex(''|sql|'',opt)=0 and left(sp,len(@db))!=@db -- check for existance of sp (tbl_jobs_setup) if @dbg=1 exec sp__printf ''--test existances'' select sp as sp_unk_name into #unksp from #steps where charindex(''|sql|'',opt)=0 and object_id(sp) is null if exists(select null from #unksp) begin exec sp__printf ''-- list of missed sp'' exec sp__select_astext ''select * from #unksp'',@header=1 drop table #unksp goto ret end drop table #unksp if @dbg=1 select * from #steps order by id if @run=0 exec sp__printf ''emails status to:%s\nsmtp:%s'',@emails,@smtp -- delete jobs if isnull(@root,'''')!='''' begin select @job=@root+''_''+isnull(@like,'''')+''#'' exec sp__printf ''deleting "%s" jobs'',@job if @run=1 exec sp__job @job,# end if isnull(@root,'''')='''' and charindex(''|add|'',@opt)=0 begin declare cs cursor local for select distinct job from #steps open cs while 1=1 begin fetch next from cs into @job if @@fetch_status!=0 break select @sql=@job+''#'' exec sp__printf ''deleting "%s" steps'',@sql if @run=1 exec sp__job @sql,# end close cs deallocate cs end -- delete jobs -- for each system & step of job declare cs cursor local for select job,sp,sched,opt from #steps order by id open cs while 1=1 begin fetch next from cs into @job,@sp,@at,@opt if @@fetch_status!=0 break if @run=0 or @dbg=1 begin select @sql=''exec sp__job\n\t@job="%s",\n\t@sp="%s",\n\t@at="%s",\n\t@opt="%s"\n\t''+ ''@emails="%s",\n\t@smtp="%s"'' select @sql=replace(@sql,''\n\t'',@crlf) select @sql=replace(@sql,''"'','''''''') exec sp__printf @sql,@job,@sp,@at,@opt,@emails,@smtp end if @run=1 exec sp__job @job=@job,@sp=@sp,@at=@at, @emails=@emails,@smtp=@smtp, @opt=@opt end -- while of cursor close cs deallocate cs goto ret -- =================================================================== errors == err_tbl: exec @ret=sp__err ''uncomplete of bad structure of setup table. See help'',@proc goto ret err_email: exec @ret=sp__err ''bad or null email:"%s". See help'',@proc,@p1=@emails goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope generate and regenerate jobs from ##jobs_setup_table## (by default "tbl_jobs_setup"). Notes the JOB and SP fields are the key for single step update; cfg "job_setup_emails,job_setup_smtp,smtp_server" are used for general emails Parameters @root is the brief name of the application @like recreate only jobs where name like @like @tt is the translate table to match TTV field (see example) accept macros: %db_name%, any ##cfg## or #cfg# (see sp__config) @opt options run execute it add do not delete jobs, add or replace only dis disabled to each added job @dbg debug mode, 1 show info Jobs table create table tbl_jobs_setup ( id int, -- give the order of steps rif sysname, -- 3 chars for person job sysname, -- @root+this become the name of job ttv sysname, -- match the @tt (see example) sp sysname, -- stored proc name (%ttv% is replaced with val in @tt) sched sysname, -- HH:MM or HHs:MMs Nm HHe:MMe opt sysname null, -- extra option passed to sp__job email sysname null -- alternative email for this step ) Utilities insert tbl_jobs_setup(id, grp, rif, job, rs, sp, sched) select id, grp, rif, job_Ext, rs, sp, sched update tbl_jobs_setup set sched= where id=??? delete from tbl_jobs_setup where job=''''???'''' insert tbl_jobs_setup( id, rif, job, ttv, sp, sched, opt ) -- --- ---------- ------------------ ----------------- ------------------------------ --------------------- ------------- select 10, ''''me'''', ''''%job1%'''', ''''*'''', ''''%sp1%'''', ''''%sched1%'''', ''''%opt1%'''' union select 20, ''''you'''', ''''%job2%'''', ''''*'''', ''''%sp2%'''', ''''%sched1%'''', null Examples sp__job_setup @tt=''''%db_name%|db1|a|utility|u|db3|c'''',@dbg=1 -- replace macro with current db_name() and if this match "db1", -- rows where ttv contains "a" are selected '' if @dbg=1 exec sp__printf ''-- @tbl=%s'',@tbl if not object_id(@tbl) is null begin select @sql=''select * from [''+@tbl+''] order by 1'' exec sp__select_astext @sql end select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__job_setup' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job_setup: -- ============================================================== sp__job_status select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job_status',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140103 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job_status') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job_status') with nowait goto skip_sp__job_status end if @ver>140103 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job_status') with nowait goto skip_sp__job_status end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job_status') with nowait if exists( select top 1 null from sys.objects where name='sp__job_status' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job_status] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140103\s.zaglio: around backward compatibility near @mins=-1 v:131223\s.zaglio: added send of email even if problem with attachment v:131129\s.zaglio: wait more time for problem of attachment locked r:131127.1100\s.zaglio: some adjustements about parameters and correct help r:131125\s.zaglio: integrating fn__job_Status to send emails every 4,16,64,256 r:131122\s.zaglio: integrating fn__job_Status and fn__config_app r:131117\s.zaglio: pretty prints and removed sp4,8; adapting to fn__job_status r:131116\s.zaglio: set @mins to -1 when @step specified and added try-catch v:130409\s.zaglio: when @mins<0 unqueue sp4/sp8 options v:121210\s.zaglio: a bug cause by sp__select_astext v:120726\s.zaglio: added @header=1 on sp__select_astext v:111130\s.zaglio: body into html and added ref and last_upd v:110715\s.zaglio: better messages v:110212\s.zaglio: better help v:100927.1010\s.zaglio: moved @mins parameter and a bug near list and @mins=-1 v:100926\s.zaglio: added with (nolock) and -1 on multi job v:100919.1100\s.zaglio: added log in opt to print txts (autoprinted if step is 1) v:100919.1000\s.zaglio: reordered params and added opt v:100919\s.zaglio: added slot management v:100724.1000\s.zaglio: a bug near -1 (last error) and calc when @mins>0 v:100626\s.zaglio: a bug near time v:100625\s.zaglio: a little bug and optimization v:100615\s.zaglio: added -1 option and a bug near selection v:100612\s.zaglio: done and tested r:100424\s.zaglio: send report of failed job of last hour t:sp__job_status ''%status%'',''raiserror'',@opt=''log'' t:sp__job_status ''%status%'',''raiserror'',@opt=''log|sel'' t:sp__job_status ''%status%'',@mins=2440,@opt=''log'' t:update cfg set val=''X'' where [key]=''job_status.test'' t:update cfg set val='' '' where [key]=''job_status.test'' t:sp__job ''sp__job_status_test'',@opt=''run'' t:sp__job_status ''%'',@opt=''sel'' t:sp__job_status ''%'',@opt=''sel'',@mins=2880 t:select * from fn__job_status(''%status%'',default,''fle'') t:msdb..sp_help_jobhistory @job_name=''sp__job_status_test'' t:sp__job_status ''%status%'',@mins=-1,@to=''*'' */ CREATE proc [dbo].[sp__job_status] @jobs nvarchar(4000) = null, -- filters for name%|name%|... @steps nvarchar(4000) = null, -- filters for step|step|... @mins int = null, -- failed of lasts minutes or job name @excludes nvarchar(4000) = null, @attach bit = null, @to nvarchar(4000) = null, -- send status to this email @body nvarchar(4000) = null, @smtp sysname = null, @ref sysname = null, @opt sysname = null, @dbg bit = 0 as begin try set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') declare @job_id uniqueidentifier select @job_id=job_id,@jobs=isnull(name,@jobs) from fn__job(@@spid) if @jobs is null goto help if @mins<-1 or @mins=0 goto help -- filters declare @filters table (id int identity,tid tinyint,dat sysname) if @jobs is null insert @filters select 1,''%'' if @steps is null insert @filters select 2,''%'' else begin insert @filters select 2,token from dbo.fn__str_table(@steps,''|'') end if not @excludes is null insert @filters select 3,''%''+token+''%'' from dbo.fn__str_table(@excludes,''|'') -- ==================================================== variable declarations == declare @previousdate datetime, @id int,@hh int, @n int,@i int, @logfile nvarchar(512),@cmd nvarchar(4000), @header int, @sql nvarchar(4000), @attaches nvarchar(4000), -- options @log bit,@ok bit,@sel bit,@nep bit,@err bit,@back bit, @fn_opt sysname create table #src(lno int identity,line nvarchar(4000)) -- ===================================================================== init == select @attach=isnull(@attach,1), @back=case @mins when -1 then 1 else 0 end, @mins=nullif(@mins,-1) if @mins is null select @mins=7*24*60,@fn_opt=''fle'' select @to=nullif(@to,''''), @smtp=nullif(@smtp,''''), @ok=charindex(''|ok|'',@opt), @sel=charindex(''|sel|'',@opt), @log=charindex(''|log|'',@opt), @nep=charindex(''|nep|'',@opt) -- ===================================================================== body == if not @job_id is null or @to=''*'' begin select @to=nullif(@to,''*'') if @to is null select @to=isnull(@to,cast( dbo.fn__config_app(''.SUPPORT_EMAIL|job_status.to'',default) as nvarchar(4000) )) if @smtp is null select @smtp=isnull(@smtp,cast( dbo.fn__config_app(''.MAIL_SMTP_SERVER|''+ ''job_status.smtp|smtp_server'',default) as nvarchar(4000) )) if @to is null or @smtp is null raiserror(''@smtp or @to not specified'',16,1) exec sp__printf ''-- auto job idf:%s to:%s(%s)'',@jobs,@to,@smtp end if not @job_id is null begin -- prevent continuos resend of message error if @nep=0 begin select top 1 @err=err,@n=n from fn__job_status(@jobs,default,''fle'') where id=@job_id if @err=1 begin if @n>4 and not @n in (16,64,128,256) begin exec sp__printf ''-- skipped because more than 4 errors'' goto ret end end else goto ret end -- select @mins=-1 this do not work properly end -- auto job determination -- ====================================================== read all job status == select h.server, s.database_name as db, fjn.[name] as job, h.step_id as sid, case when h.sql_severity>10 then ''X'' else '''' end S, dbo.fn__str_pad(convert(sysname,h.run_date),8,default,default,default) as run_date, dbo.fn__str_pad(convert(sysname,h.run_time),6,default,default,default) as run_time, fjn.n as n, h.run_duration secs, s.step_name as step, isnull((select convert(sysname,si.val1)+''\''+convert(sysname,si.val2) from dbo.fn__script_info(s.command,''vr'',0) si ),replace(replace(replace( left(s.command,40)+case when len(s.command)>40 then ''...'' else '''' end, char(13),'' ''),char(10),'' ''),'' '','' '') ) as last_upd, -- h.sql_severity, left(''..''+ replace(replace( replace(replace( replace(replace( replace(replace( replace(replace( h.message, ''[SQLSTATE 01000]'',''''),''(Message 50000)'',''''), ''[SQLSTATE 42000]'',''''),''(Error 50000)'',''''), char(13),'' ''),char(10),'' ''), ''..'',''''),''The step '',''''), '' '','' ''),''(Message 0)'','''') ,128) as [message], s.output_file_name into #failures from fn__job_status(@jobs,@mins,@fn_opt) fjn join msdb.dbo.sysjobhistory h with (nolock) on h.job_id=fjn.id and h.run_date=fjn.run_date and h.run_time between fjn.from_time and fjn.run_time join msdb.dbo.sysjobsteps s with (nolock) on h.job_id = s.job_id and h.step_id=s.step_id join @filters flts on flts.tid=2 and s.step_name like flts.dat left join @filters fltexj on fltexj.tid=3 and h.message like fltexj.dat where charindex(''exec sp__job_status'',s.command)=0 and left(s.command,14)!=''sp__job_status'' and fltexj.id is null order by h.run_date desc,server,row desc,h.run_time desc,h.step_id desc -- ================================================================= @mins=-1 == -- if calling from job... if not @job_id is null or @back=1 begin delete f from #failures f left join ( select top 1 * from #failures order by run_date desc,run_time desc,sid desc ) ff on ff.run_date=f.run_date and ff.run_time=f.run_time and ff.sid=f.sid where ff.sid is null if ''X''!=( select top 1 s from #failures order by run_date desc,run_time desc,sid desc ) goto ret end -- from job if @attach=1 begin /* 111130\s.zaglio: converted into html-body select @attaches=''select * from #failures order by instance_id desc'' */ select @attaches=coalesce(@attaches+'';'','''')+output_file_name from ( -- optimize files for more steps select distinct output_file_name from #failures where coalesce(output_file_name,'''')!='''' ) sq if @dbg=1 exec sp__printf ''-- %s:attaches:%s'',@proc,@attaches end select @n=count(*) from #failures if @n>0 begin -- sp__job_status @mins=-1,@jobs=''spj_test'',@opt=''ok'',@dbg=1 if @dbg=1 exec sp__printf ''-- %s:%d failed job steps found for jobs %s'', @proc,@n,@jobs if not @to is null begin insert #src select '''' insert #src select ''jobs:''+@jobs if not @body is null insert #src select @body exec sp__select_astext '' select SERVER,DB,JOB,SID,S,RUN_DATE,RUN_TIME,N,STEP,LAST_UPD, MESSAGE from #failures order by run_date desc,run_time desc,sid desc '', @out=''#src'',@opt=''html'',@header=1,@dbg=0 insert #src select '''' declare @subj sysname select @subj=quotename(dbo.fn__servername(null)) +''.sp__job_status failed steps for jobs: '' +coalesce(@jobs,''ALL'') -- retry because some time the agent block the log select @n=1 while @n<4 begin try exec sp__printf ''-- send email (%d)'',@n exec sp__email @to=@to, @subj=@subj, @body=''#src'', @attach=@attaches, @smtp=@smtp, @dbg=@dbg break end try begin catch select @n=@n+1 if @n=4 begin select @sql=error_message() exec sp__printf ''%s'',@sql insert #src select ''
''+@sql+''
'' insert #src select @attaches+''

'' exec sp__email @to=@to, @subj=@subj, @body=''#src'', @smtp=@smtp, @dbg=@dbg end else waitfor delay ''00:00:02'' end catch end -- @n>0 else begin -- show only to console if @ok=0 -- and charindex(''|log|'',@opt)=0 --or ((select count(*) from #failures)>1 begin -- then show steps with log select @sql='' select * from #failures order by run_date desc,run_time desc,sid desc '' if @n>20 select @header=2 else select @header=1 if @sel=1 exec(@sql) else exec sp__select_astext @sql,@header=@header end -- ########################## -- ## -- ## print log -- ## -- ######################################################## if @log=1 begin -- first show steps without log if exists( select top 1 null from #failures where isnull(output_file_name,'''')='''' ) begin select @sql='' select ''''step without log'''' info,* from #failures where isnull(output_file_name,'''''''')='''''''' order by run_date desc,run_time desc,sid desc '' if @sel=1 exec(@sql) else begin exec sp__printf '''' exec sp__select_astext @sql,@header=1 end end -- steps without log -- sp__job_status ''%status%'',@opt=''log'' declare cs cursor local for select output_file_name from #failures order by run_date desc,run_time desc,sid desc open cs while 1=1 begin fetch next from cs into @logfile if @@fetch_status!=0 break if not isnull(@logfile,'''')='''' begin select @cmd=''type "''+@logfile+''"'' truncate table #src insert #src exec master..xp_cmdshell @cmd update #src set line= replace(replace( replace(replace( line, ''[SQLSTATE 01000]'',''''),''(Message 50000)'',''''), ''[SQLSTATE 42000]'',''''),''(Error 50000)'','''') exec sp__printf '''' exec sp__prints @logfile if @sel=1 exec(''select line [''+@logfile+''] from #src order by lno'') else exec sp__print_table ''#src'' -- exec sp__select_astext ''select * from #src order by 1'',@header=0 end -- print log end -- cursor cs close cs deallocate cs end -- print log end -- print failed step info end -- if there is history else exec sp__printf ''-- %s:no wrong step found for jobs %s in the lasts %d mins'', @proc,@jobs,@mins dispose: drop table #failures drop table #src goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope print or send a report about jobs Notes - can be added as last step of a job - %obj% can automatically detect running job - %obj% uses fn__config_app to get values for @smtp and @to Parameters @jobs filter jobs (job1|job2|...) (default is %) @steps filter steps (step1|step2|...) (default is %) @mins is the number of minutes before now to watch (default is -1) -1 means from last error, if last run was wrong 1440 means last 24h 2880 means last two days @excludes filter jobs for exclusions (job1|job2|...) @attach attach output files with message (default=1) @to emails to sent report if null or empty will be searched: 1st in application config: SUPPORT_EMAIL 2nd in utility config: job_status.to @body optional email message text @smtp smtp server name or ip or if null or empty will be searched: 1st in application config: MAIL_SMTP_SERVER 2nd in utility config: job_status.smtp 3rd in utility config: smtp_server @ref system or person reference for step in case of stored proc., the column last_upd report the date and name of last that has changed the code @opt options log show the txt of log sel show results as select ok show also not failed lines nep do not apply continuous error prevention Examples sp__job_status -- show this help and jobs with failed steps sp__job_status "%status%" -- show info about jobs that contain "status" -- and limited to last failure to now sp__job_status "%status%",@mins=2880 -- show info about jobs that contain "status" -- of lasts two days sp__job_status "%status%",@opt="log" -- show info about failed steps with logs (.txt) sp__job_status "%status%",@opt="ok|log" -- show info about all steps of jobs (with .txt) sp__job_status "%",@opt="sel|ok|log" -- show all steps as select '' select job_failed as [job_failed(jf)],nsf, substring(convert(sysname,last_run),1,8) last_datef, substring(convert(sysname,last_run),9,6) last_timef into #sp__job_status_list from ( select [name] as job_failed, (select count(*) from msdb..sysjobhistory h with (nolock) where h.job_id=j.job_id and h.run_status = 0 and h.sql_severity>0) as nsf, (select max(convert(bigint,h.run_date)*1000000+h.run_time) as last_run from msdb..sysjobhistory h with (nolock) where h.job_id=j.job_id and h.run_status = 0 and h.sql_severity>0) as last_run from msdb..sysjobs j with (nolock) ) j where nsf>0 if @@rowcount>0 select *, case when last_datef=convert(sysname,getdate(),112) then ''*'' else '''' end as [@] from #sp__job_Status_list order by last_datef desc,last_timef desc drop table #sp__job_status_list select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- sp__job_status' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job_status: -- ================================================================ sp__job_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140103 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job_test') with nowait goto skip_sp__job_test end if @ver>140103 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job_test') with nowait goto skip_sp__job_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job_test') with nowait if exists( select top 1 null from sys.objects where name='sp__job_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:job,test,auto,find,name,running v:140103\s.zaglio: callable from sp__utility_setup v:130209\s.zaglio: test func fn__job t:sp__job_test @dbg=1 */ CREATE proc sp__job_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @run bit,@setup bit, @sp sysname -- =========================================================== initialization == select @run=charindex(''|run|'',@opt),@setup=charindex(''|setup|'',@opt) -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == if @run=0 begin select @sp=@proc+'' @opt=''''run'''''' -- delete prev job exec sp__job @proc,''#'' exec sp__job @proc,@sp,@opt=''sql|run|nolog'' -- exec sp__job_wait @proc waitfor delay ''00:00:01'' if @dbg=0 exec sp__job @proc,''#'' if object_id(''tmp_sp__job_test'') is null raiserror(''test failed'',16,1) if @setup=0 select * from tmp_sp__job_test drop table tmp_sp__job_test end else begin if not object_id(''tmp_sp__job_test'') is null drop table tmp_sp__job_test create table tmp_sp__job_test( job_id sql_variant null,name sql_variant null, loginname sql_variant null,login sql_variant null, ologin sql_variant null,ja sql_variant null ) insert into tmp_sp__job_test(job_id,name,loginname,ja) select *,dbo.fn__job_agent() from fn__job(@@spid) end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. if @setup=1 goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test if fn__job works in this system; if it do not work, the sp__job_status and all the SP called from a job, do not understand that they are running into a job. Parameters [param] [desc] @opt options run run the test (called by itself from a temporary job) setup when called by sp__utility_setup @dbg debug info 1 do not delete temporary job Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__job_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job_test: -- ================================================================ sp__job_wait select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__job_wait',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090504 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__job_wait') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__job_wait') with nowait goto skip_sp__job_wait end if @ver>090504 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__job_wait') with nowait goto skip_sp__job_wait end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__job_wait') with nowait if exists( select top 1 null from sys.objects where name='sp__job_wait' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__job_wait] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090504\S.Zaglio: from http://www.sqlservercentral.com/scripts/Miscellaneous/30124/ t: to study and integrate into sp__job */ CREATE PROCEDURE [sp__job_wait] @jobs nvarchar(2000), @is_running bit = 0, @max_seconds int = 10, @pause_seconds int = null, @retrying_equals_running bit = 0 AS /* Procedure waits until the indicated job or jobs, have the status of running or stopped. It will wait until it has reached the max wait time, checking the status every 5 seconds. It returns the results of the job. 1 - successfull 2 - retrying 3 - cancelled -1 - not started -2 - executing 0 - failed */ declare @job nvarchar(50), @b int, @e int, @running int, @result int, @tries int, @is_sysadmin INT, @job_owner sysname, @pause_string nvarchar(9), @pause_number int, @max_tries int, @last_run_date int, @last_run_time int, @run_date int, @run_time int, @minutes int, @hours int, @seconds int begin set nocount on set @jobs = rtrim(ltrim(@jobs)) if right(@jobs,1)<>'','' begin set @jobs = @jobs + '','' end -- create temp tables create table #wait_job_status ( job_id uniqueidentifier not null, last_run_date int not null, last_run_time int not null, next_run_date int not null, next_run_time int not null, next_run_schedule_id int not null, requested_to_run int not null, -- BOOL request_source int not null, request_source_id sysname null, running int not null, -- BOOL current_step int not null, current_retry_attempt int not null, job_state int not null ) create table #wait_job_list ( [name] nvarchar(100) not null primary key ) -- set variables for status set @is_sysadmin = ISNULL(IS_SRVROLEMEMBER(N''sysadmin''), 0) set @job_owner = SUSER_SNAME() if isnull(@pause_seconds,0)<1 begin set @pause_number = floor(@max_seconds / (case when @max_seconds>30 then 4 else 2 end)) set @pause_number = case when @pause_number > 15 then 15 when @pause_number < 1 then 1 else @pause_number end end else begin set @pause_number = @pause_seconds end select @hours = floor(@pause_number / 3600), @minutes = floor((@pause_number - (@hours * 3600)) / 60), @seconds = (@pause_number - (@hours * 3600) - (@minutes * 60)), @pause_string = right(''00''+convert(nvarchar,@hours),2)+'':''+ right(''00''+convert(nvarchar,@minutes),2)+'':''+ right(''00''+convert(nvarchar,@seconds),2) set @max_tries = @max_seconds / @pause_number set @b = 0 set @e = CHARINDEX('','',@jobs,@b+1) while (@e>0) begin set @job = SUBSTRING(@jobs,@b+1,@e-(@b+1)) insert into #wait_job_list([name]) values(lower(ltrim(rtrim(@job)))) set @b = @e set @e = CHARINDEX('','',@jobs,@b+1) end -- begin status check set @running = case when @is_running=1 then 0 else 1 end set @tries = 0 set @last_run_date=0 set @last_run_time=0 set @run_date=0 set @run_time=0 while @running= case when @is_running=1 then 0 else 1 end and @tries<=@max_tries and (@last_run_date=@run_date) and (@last_run_time=@run_time) begin set @running = @is_running set @tries = @tries + 1 set @result = 0 truncate table #wait_job_status insert into #wait_job_status exec master..xp_sqlagent_enum_jobs @is_sysadmin, @job_owner select @running = case when @is_running = 1 then 0 else 1 end, @last_run_date = case when @tries=1 then x.last_run_date else @last_run_date end, @last_run_time = case when @tries=1 then x.last_run_time else @last_run_time end, @run_date = x.last_run_date, @run_time = x.last_run_time from #wait_job_status x inner join msdb..sysjobs s on x.job_id=s.job_id left join msdb..sysjobhistory h on h.job_id=x.job_id and h.step_id=0 and h.run_date=x.last_run_date and h.run_time=x.last_run_time where lower(s.[name]) in (select [name] from #wait_job_list) and case when (@is_running=1 and (x.[running]<1 or (x.[running]>0 and x.[job_state]<>1 and @retrying_equals_running=0))) or (@is_running=0 and x.[running]>0 and (x.[job_state]=1 or @retrying_equals_running=1)) then 1 else 0 end = 1 if (@running=case when @is_running=1 then 0 else 1 end) and (@last_run_date=@run_date) and (@last_run_time=@run_time) begin -- job (or jobs) are not in correct state, so wait - then try again waitfor delay @pause_string end else begin -- job is in correct state, so pull status select @result = case when x.[job_state]<>1 and x.[running]=1 then 2 else h.[run_status] end from #wait_job_status x inner join msdb..sysjobs s on x.job_id=s.job_id left join msdb..sysjobhistory h on h.job_id=x.job_id and h.step_id=0 and h.run_date=x.last_run_date and h.run_time=x.last_run_time where lower(s.[name]) in (select [name] from #wait_job_list) order by case h.[run_status] when 3 then 2 when 1 then 3 else 1 end desc end end if @tries>@max_tries begin select @result = case when @is_running=1 then -1 else -2 end end -- drop temp tables drop table #wait_job_status drop table #wait_job_list -- return results return @result end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__job_wait: -- ==================================================================== sp__link select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__link',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090517 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__link') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__link') with nowait goto skip_sp__link end if @ver>090517 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__link') with nowait goto skip_sp__link end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__link') with nowait if exists( select top 1 null from sys.objects where name='sp__link' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__link] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090517\S.Zaglio: create a link to a remote object */ create proc sp__link @obj sysname,@server sysname, @db sysname=null, @uid sysname=''sa'', @pwd sysname='''',@drop bit=0,@dbg bit=0 as begin set nocount on declare @wid sysname select @wid='''' declare @sql nvarchar(4000) if @db is null select @db=db_name() select @sql =''create view [''+@obj+ ''] as '' +''select * from opendatasource(''''SQLOLEDB'''','' +'''''''' +''Persist Security Info=True;UID=''+@uid+'';'' +''Initial Catalog=''+@db+'';'' +''SERVER=''+@server+'';'' +''Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;'' +''Workstation ID=''+@wid +''Use Encryption for Data=False;Tag with column collation when possible=False'' +'''''''' +'').''+@db+''.dbo.[''+@obj+''] rowset_1'' if @dbg=1 print @sql if @drop=1 exec sp__drop @obj exec(@sql) end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__link: -- ==================================================================== sp__lock select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__lock',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120905 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__lock') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__lock') with nowait goto skip_sp__lock end if @ver>120905 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__lock') with nowait goto skip_sp__lock end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__lock') with nowait if exists( select top 1 null from sys.objects where name='sp__lock' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__lock] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120905\s.zaglio: moved out the help v:120827\s.zaglio: a small bug v:101211\s.zaglio: replace call of sp_lock v:100919\s.zaglio: added WITH NO_INFOMSGS to not show dbcc out v:100615\s.zaglio: added with nolock everywhare v:091221\s.zaglio: a different approach because alter table on # don''t work. Better use select into v:091123\s.zaglio: replaced use of object_name because is blocked by transaction and not influenced by set trans... v:091116\s.zaglio: help find locks (replace also old sp__find_root_blocker) s:sp__lock_ex t:sp__lock @@spid t:sp__lock ''#lock'' t:sp__lock @dbg=1 t:print @@trancount t:sp__lock @blocking=1 -- sp__lock 7 -- sp_lock t:select * from master..sysprocesses where spid=7 t:sp__run_cmd ''net start'' -- sp__run_cmd ''net stop "SQLAgent$WEBAPP" & net start "SQLAgent$WEBAPP"'' t:sp__lock 70,@tsql=1 */ CREATE proc [dbo].[sp__lock] ( @spid_obj_login_root sysname=null, @db sysname = null, @tsql bit=null, @blocking bit=0, @dbg bit=0 ) as begin -- declare @spid_obj_login_root sysname,@db sysname,@dbg bit set @dbg=1 set nocount on set transaction isolation level read uncommitted declare @spid int, @obj sysname, @name sysname,@proc sysname declare @i int,@n int,@sql nvarchar(4000),@id int declare @timer datetime select @proc=object_name(@@procid) declare @sysobjects table (id int, name sysname) select @timer=current_timestamp if @spid_obj_login_root is null exec sp__usage @proc else select @tsql=1 select @tsql=coalesce(@tsql,0) if isnumeric(@spid_obj_login_root)=1 select @spid=convert(int,@spid_obj_login_root) else select @obj=@spid_obj_login_root+''%'' create table #lock1 ( spid int, dbid int, objid int, indid int, type nchar(5), resource sysname, mode sysname, status sysname ) -- select * from master..syslocks exec sp__printf ''-- sp__lock:%T: read from sp_lock'',''%t'' -- ''%t'' otherwise do not print date insert into #lock1 select convert (smallint, req_spid) As spid, rsc_dbid As [dbid], rsc_objid As [ObjId], rsc_indid As IndId, substring (v.name, 1, 4) As Type, substring (rsc_text, 1, 32) as Resource, substring (u.name, 1, 8) As Mode, substring (x.name, 1, 5) As Status -- select * from master.dbo.syslockinfo with (nolock), master.dbo.spt_values v with (nolock), master.dbo.spt_values x with (nolock), master.dbo.spt_values u with (nolock) -- SELECT * FROM sys.dm_tran_locks where master.dbo.syslockinfo.rsc_type = v.number and v.type = ''LR'' and master.dbo.syslockinfo.req_status = x.number and x.type = ''LS'' and master.dbo.syslockinfo.req_mode + 1 = u.number and u.type = ''L'' order by spid -- select * from master..sysprocesses p select * into #processes from master..sysprocesses p with (nolock) -- where p.status!=''sleeping'' ! nope coz can be active lock on (h)old spid exec sp__printf ''-- sp__lock:%T: altering #lock'',''%t'' -- ''%t'' otherwise do not print date select identity(int,1,1) as id, convert(sysname,null) as [db_name], convert(sysname,null) as obj_name, convert(sysname,null) as p_status, convert(sysname,null) as sql, convert(sysname,null) as login, convert(sysname,null) as host, convert(int,null) waittime, convert(int,null) open_trans, convert(datetime,null) last_batch, convert(int,null) blocking, convert(int,null) n_locks, #lock1.* into #lock from #lock1 with (nolock) drop table #lock1 -- capture sql as first to not loose it if @tsql=1 begin create table #dbccout(language_event sysname,parameters INT,event_info NVARCHAR(4000)) exec sp__printf ''-- sp__lock:%T: get cmds'',''%t'' -- ''%t'' otherwise do not print date select @i=min(id),@n=max(id) from #lock with (nolock) while (@i<=@n) begin select @id=spid from #lock with (nolock) where id=@i truncate table #dbccout select @sql=''insert into #dbccout exec(''''dbcc inputbuffer(''+convert(sysname,@id)+'') with no_infomsgs'''')'' if @dbg=1 exec sp__printf @sql exec(@sql) update l set sql=left(ltrim(rtrim(d.event_info)),128) from #lock l with (nolock) join #dbccout d with (nolock) on l.spid=@id select @i=@i+1 end -- while drop table #dbccout end -- @tsql exec sp__printf ''-- sp__lock:%T: update other data'',''%t'' -- ''%t'' otherwise do not print date -- update other data (select * from #processes) update l set host=p.hostname,waittime=p.waittime, p_status=p.status, [login]=p.loginame, open_trans=p.open_tran,last_batch=p.last_batch, blocking=p2.spid, n_locks=(select count(*) from #lock with (nolock) where #lock.spid=l.spid group by(spid)) from #lock l with (nolock) join #processes p with (nolock) on l.spid=p.spid left join #processes p2 with (nolock) on p.spid=p2.blocked -- format 1st row to conditionate the output /* insert into #lock(spid,n_locks, [db_name],obj_name,[type],mode,[login],host,[sql]) select 0,999, ''-db_name-'',''-obj_name----'',''--'',''--'',''-login-'',''-host-'',''-sql----------------'' */ exec sp__printf ''-- sp__lock:%T: complete db name and object name'',''%t'' -- ''%t'' otherwise do not print date update l set [db_name]=d.name from #lock l with (nolock) join master..sysdatabases d with (nolock) on l.dbid=d.dbid /* declare @last_id int,@last_name sysname select @i=min(id),@n=max(id) from #lock with (nolock) while (@i<=@n) begin select @id=l.objid,@name=l.[db_name] from #lock l with (nolock) where id=@i if @last_id is null or @last_id!=@id begin select @sql=''select @name=name from ''+quotename(@name)+''..sysobjects with (nolock) where id=''+convert(sysname,@id)+'''' if @dbg=1 exec sp__printf @sql select @name=@name+''(''+convert(sysname,@id)+'')'' exec sp_executesql @sql,N''@name sysname out'',@name=@name out end update #lock set obj_name=@name where id=@i select @i=@i+1,@last_id=@id,@last_name=@name end -- while */ -- sp__lock @dbg=1 select @sql=null select @sql=coalesce(@sql,'''')+'' update #lock set obj_name=o.name from #lock l with (nolock) join ''+quotename([db_name])+''..sysobjects o with (nolock) on l.objid=o.id'' from #lock l group by [db_name] if @dbg=1 and len(@sql)>3990 exec sp__printf ''%s'',@sql exec(@sql) exec sp__printf ''-- sp__lock:%T: output'',''%t'' -- ''%t'' otherwise do not print date -- select count(*) from #lock if @dbg=1 select [db_name],spid from #lock with (nolock) -- master..xp_fixeddrives /* show lock in order: * more locked objs * lock most far (waittime desc or last_batch-current_timestamp) * that have more open_trans * that have a object name * lock of different login name */ select @n=count(*) from #lock l with (nolock) exec sp__printf ''-- sp__lock:%T: filtering %d records by:%s or spid %d'',@n,@obj,@spid -- declare @timer datetime select l.spid,l.[db_name],replace(l.obj_name,''___'',''.'') as obj_name,l.type,l.mode, left(l.login,16) as [login],l.host,l.sql,l.p_status,l.resource,l.open_trans,l.status, datediff(ss,l.last_batch,@timer) as rsecs,l.blocking,l.n_locks from #lock l with (nolock) where (@spid is null or l.spid=@spid) and ( (@obj is null or l.obj_name like @obj) or (@obj is null or l.login like @obj) ) and ([type]!=''DB'' and mode!=''S'') -- shared db locks and (not l.blocking is null or @blocking=0) order by n_locks desc,l.spid,[db_name],obj_name -- datediff(ss,l.last_batch,@timer) desc,l.open_trans desc,l.obj_name desc exec sp__printf ''-- sp__lock:%T: drop temp tables'',''%t'' -- ''%t'' otherwise do not print date drop table #processes drop table #lock end -- sp__lock' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__lock: -- ================================================================= sp__lock_ex select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__lock_ex',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130203 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__lock_ex') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__lock_ex') with nowait goto skip_sp__lock_ex end if @ver>130203 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__lock_ex') with nowait goto skip_sp__lock_ex end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__lock_ex') with nowait if exists( select top 1 null from sys.objects where name='sp__lock_ex' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__lock_ex] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130203\s.zaglio: added cxpackets locks v:120911\s.zaglio: added warning on missing help v:120905\s.zaglio: added code for finding the SPID of running jobs v:111213\s.zaglio: blocking into #temp because out of memory v:111129\s.zaglio: added view of blocking in current database v:110921\s.zaglio: emaciated v:110916\s.zaglio: added list of n locks x db v:101110\s.zaglio: removed original_login_name,original_security_id(sp3) to make it compatible with sp2 v:101012\s.zaglio: not tested but probably better than my sp__lock t:exec sp__lock_ex ; exec sp__lock_ex @procdata=''a'' c: originally from http://www.sommarskog.se/sqlutil/beta_lockinfo.sp i removed comments and text mode to reduce compile time */ CREATE proc sp__lock_ex @allprocesses bit = 0, @procdata char(1) = null, @debug bit = 0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if dbo.fn__ismssql2k()=0 begin -- cx packets locks select session_id , exec_context_id , wait_type , wait_duration_ms , blocking_session_id from sys.dm_os_waiting_tasks where session_id > 50 order by session_id, exec_context_id -- number of lock records per database select count(*) as ''numberoflockrecords'', db_name(resource_database_id) from master.sys.dm_tran_locks group by resource_database_id; -- ========================================= finding the SPID of running jobs == -- from http://social.msdn.microsoft.com/Forums/eu/transactsql/thread/8af7ac39-7b09-4b84-9c1c-95573c7350d8 DECLARE @record_id int, @SQLProcessUtilization int, @CPU int,@EventTime datetime--,@MaxCPUAllowed int select top 1 @record_id =record_id, @EventTime=dateadd(ms, -1 * ((SELECT ms_ticks from sys.dm_os_sys_info) - [timestamp]), GetDate()),-- as EventTime, @SQLProcessUtilization=SQLProcessUtilization, --SystemIdle, --100 - SystemIdle - SQLProcessUtilization as OtherProcessUtilization, @CPU=SQLProcessUtilization + (100 - SystemIdle - SQLProcessUtilization) --as CPU_Usage from ( select record.value(''(./Record/@id)[1]'', ''int'') as record_id, record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]'', ''int'') as SystemIdle, record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]'', ''int'') as SQLProcessUtilization, timestamp from ( select timestamp, convert(xml, record) as record from sys.dm_os_ring_buffers where ring_buffer_type = N''RING_BUFFER_SCHEDULER_MONITOR'' and record like ''%%'') as x ) as y order by record_id desc SELECT x.session_id as [Sid], COALESCE(x.blocking_session_id, 0) as BSid, @CPU as CPU, @SQLProcessUtilization as SQL, x.Status, x.TotalCPU as [T.CPU], x.Start_time, CONVERT(nvarchar(30), getdate()-x.Start_time, 108) as Elap_time, --x.totalElapsedTime as ElapTime, x.totalReads as [T.RD], -- total reads x.totalWrites as [T.WR], --total writes x.Writes_in_tempdb as [W.TDB], ( SELECT substring(text,x.statement_start_offset/2, (case when x.statement_end_offset = -1 then len(convert(nvarchar(max), text)) * 2 else x.statement_end_offset end - x.statement_start_offset+3)/2) FROM sys.dm_exec_sql_text(x.sql_handle) FOR XML PATH(''''), TYPE ) AS Sql_text, db_name(x.database_id) as dbName, (SELECT object_name(objectid) FROM sys.dm_exec_sql_text(x.sql_handle)) as object_name, x.Wait_type, x.Login_name, x.Host_name, CASE LEFT(x.program_name,15) WHEN ''SQLAgent - TSQL'' THEN ( select top 1 ''SQL Job = ''+j.name from msdb.dbo.sysjobs (nolock) j inner join msdb.dbo.sysjobsteps (nolock) s on j.job_id=s.job_id where right(cast(s.job_id as nvarchar(50)),10) = RIGHT(substring(x.program_name,30,34),10) ) WHEN ''SQL Server Prof'' THEN ''SQL Server Profiler'' ELSE x.program_name END as Program_name, x.percent_complete, x.percent_complete, ( SELECT p.text FROM ( SELECT sql_handle,statement_start_offset,statement_end_offset FROM sys.dm_exec_requests r2 WHERE r2.session_id = x.blocking_session_id ) AS r_blocking CROSS APPLY ( SELECT substring(text,r_blocking.statement_start_offset/2, (case when r_blocking.statement_end_offset = -1 then len(convert(nvarchar(max), text)) * 2 else r_blocking.statement_end_offset end - r_blocking.statement_start_offset+3)/2) FROM sys.dm_exec_sql_text(r_blocking.sql_handle) FOR XML PATH(''''), TYPE ) p (text) ) as blocking_text, (SELECT object_name(objectid) FROM sys.dm_exec_sql_text( (select top 1 sql_handle FROM sys.dm_exec_requests r3 WHERE r3.session_id = x.blocking_session_id))) as blocking_obj FROM ( SELECT r.session_id, s.host_name, s.login_name, r.start_time, r.sql_handle, r.database_id, r.blocking_session_id, r.wait_type, r.status, r.statement_start_offset, r.statement_end_offset, s.program_name, r.percent_complete, SUM(cast(r.total_elapsed_time as bigint)) /1000 as totalElapsedTime, --CAST AS BIGINT to fix invalid data convertion when high activity SUM(cast(r.reads as bigint)) AS totalReads, SUM(cast(r.writes as bigint)) AS totalWrites, SUM(cast(r.cpu_time as bigint)) AS totalCPU, SUM(tsu.user_objects_alloc_page_count + tsu.internal_objects_alloc_page_count) AS writes_in_tempdb FROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id JOIN sys.dm_db_task_space_usage tsu ON s.session_id = tsu.session_id and r.request_id = tsu.request_id WHERE r.status IN (''running'', ''runnable'', ''suspended'') GROUP BY r.session_id, s.host_name, s.login_name, r.start_time, r.sql_handle, r.database_id, r.blocking_session_id, r.wait_type, r.status, r.statement_start_offset, r.statement_end_offset, s.program_name, r.percent_complete ) x where x.session_id <> @@spid order by x.totalCPU desc -- ========================================= finding the SPID of running jobs == --View Blocking in Current Database --Author: Timothy Ford --http://thesqlagentman.com --drop table #blocking select dtl.resource_type, case when dtl.resource_type in (''database'', ''file'', ''metadata'') then dtl.resource_type when dtl.resource_type = ''object'' then object_name(dtl.resource_associated_entity_id) when dtl.resource_type in (''key'', ''page'', ''rid'') then ( select object_name([object_id]) from sys.partitions where sys.partitions.hobt_id = dtl.resource_associated_entity_id ) else ''unidentified'' end as requested_object_name, dtl.request_mode, dtl.request_status, dowt.wait_duration_ms, dowt.wait_type, dowt.session_id as [blocked_session_id], sp_blocked.[loginame] as [blocked_user], convert(nvarchar(max),null) as [blocked_command], -- dest_blocked.[text] as [blocked_command], dowt.blocking_session_id, sp_blocking.[loginame] as [blocking_user], convert(nvarchar(max),null) as [blocking_command], -- dest_blocking.[text] as [blocking_command], dowt.resource_description, sp_blocked.[sql_handle] as sp_blocked_sql_handle, sp_blocking.[sql_handle] as sp_blocking_sql_handle into #blocking -- select * from sys.dm_tran_locks as dtl with (nolock) inner join sys.dm_os_waiting_tasks as dowt with (nolock) on dtl.lock_owner_address = dowt.resource_address inner join sys.sysprocesses as sp_blocked with (nolock) on dowt.[session_id] = sp_blocked.[spid] inner join sys.sysprocesses as sp_blocking with (nolock) on dowt.[blocking_session_id] = sp_blocking.[spid] update #blocking set [blocked_command]=dest_blocked.[text], [blocking_command]=dest_blocking.[text] from #blocking b cross apply sys.[dm_exec_sql_text](sp_blocked_sql_handle) as dest_blocked cross apply sys.[dm_exec_sql_text](sp_blocking_sql_handle) as dest_blocking -- where dtl.[resource_database_id] = db_id() select * from #blocking drop table #blocking end -- view of n of locks and blocking -- version check declare @version varchar(20) select @version = convert(varchar, serverproperty(''productversion'')) if @version not like ''[0-9][0-9].%'' select @version = ''0'' + @version if @version < ''09.00.3042'' begin raiserror(''beta_lockinfo requires sql server 2005 sp2 or later'', 16, 127) goto ret end -- compatibility level check if (select compatibility_level from sys.databases where name = db_name()) < 90 begin raiserror(''you cannot install beta_lockinfo in database with compat.level 80 or lower.'', 16, 127) goto ret end -- this table holds the information in sys.dm_tran_locks, aggregated -- on a number of items. note that we do not include subthreads or -- requests in the aggregation. declare @locks table ( session_id int not null, req_mode varchar(60) collate latin1_general_bin2 not null, rsc_type varchar(60) collate latin1_general_bin2 not null, rsc_subtype varchar(60) collate latin1_general_bin2 not null, req_status varchar(60) collate latin1_general_bin2 not null, req_owner_type varchar(60) collate latin1_general_bin2 not null, rsc_description nvarchar(256) collate latin1_general_bin2 null, database_id int not null, entity_id bigint null, cnt int not null, activelock as case when rsc_type = ''database'' and req_status = ''grant'' then convert(bit, 0) else convert(bit, 1) end, ident int identity primary key, rowno int null -- set per session_id if @procdata is f. ) -- this table holds the translation of entity_id in @locks. this is a -- temp table since we access it from dynamic sql. the type_desc is used -- for allocation units. create table #objects ( idtype char(4) not null check (idtype in (''obj'', ''hobt'', ''au'', ''misc'')), database_id int not null, entity_id bigint not null, hobt_id bigint null, object_name nvarchar(550) collate latin1_general_bin2 null, type_desc varchar(60) collate latin1_general_bin2 null, primary key clustered (database_id, idtype, entity_id), unique nonclustered (database_id, entity_id, idtype) ) -- this table captures sys.dm_os_waiting_tasks and later augment it with -- data about the block chain. a waiting task always has a always has a -- task address, but the blocker may be idle and without a task. -- all columns for the blocker are nullable, as we add extra rows for -- non-waiting blockers. declare @dm_os_waiting_tasks table (wait_session_id smallint not null, wait_task varbinary(8) not null, block_session_id smallint null, block_task varbinary(8) null, wait_type varchar(60) collate latin1_general_bin2 null, wait_duration_ms bigint null, -- the level in the chain. level 0 is the lead blocker. null for -- tasks that are waiting, but not blocking. block_level smallint null, -- the lead blocker for this block chain. lead_blocker_spid smallint null, -- whether the block chain consists of the threads of the same spid only. blocksamespidonly bit not null default 0, unique clustered (wait_session_id, wait_task, block_session_id, block_task), unique (block_session_id, block_task, wait_session_id, wait_task) ) -- this table holds information about transactions tied to a session. -- a session can have multiple transactions when there are multiple -- requests, but in that case we only save data about the oldest -- transaction. declare @transactions table ( session_id smallint not null, is_user_trans bit not null, trans_start datetime not null, trans_since decimal(10,3) null, trans_type int not null, trans_state int not null, dtc_state int not null, is_bound bit not null, primary key (session_id) ) -- this table holds information about all sessions and requests. declare @procs table ( session_id smallint not null, task_address varbinary(8) not null, exec_context_id int not null, request_id int not null, spidstr as ltrim(str(session_id)) + case when exec_context_id <> 0 or request_id <> 0 then ''/'' + ltrim(str(exec_context_id)) + ''/'' + ltrim(str(request_id)) else '''' end, is_user_process bit not null, orig_login nvarchar(128) collate latin1_general_bin2 null, current_login nvarchar(128) collate latin1_general_bin2 null, session_state varchar(30) collate latin1_general_bin2 not null, task_state varchar(60) collate latin1_general_bin2 null, proc_dbid smallint null, request_dbid smallint null, host_name nvarchar(128) collate latin1_general_bin2 null, host_process_id int null, endpoint_id int not null, program_name nvarchar(128) collate latin1_general_bin2 null, request_command varchar(32) collate latin1_general_bin2 null, trancount int not null, session_cpu int not null, request_cpu int null, session_physio bigint not null, request_physio bigint null, session_logreads bigint not null, request_logreads bigint null, isclr bit not null default 0, nest_level int null, now datetime not null, login_time datetime not null, last_batch datetime not null, last_since decimal(10,3) null, curdbid smallint null, curobjid int null, current_stmt nvarchar(max) collate latin1_general_bin2 null, sql_handle varbinary(64) null, plan_handle varbinary(64) null, stmt_start int null, stmt_end int null, current_plan xml null, rowno int not null, block_level tinyint null, block_session_id smallint null, block_exec_context_id int null, block_request_id int null, blockercnt int null, block_spidstr as ltrim(str(block_session_id)) + case when block_exec_context_id <> 0 or block_request_id <> 0 then ''/'' + ltrim(str(block_exec_context_id)) + ''/'' + ltrim(str(block_request_id)) else '''' end + case when blockercnt > 1 then '' (+'' + ltrim(str(blockercnt - 1)) + '')'' else '''' end, blocksamespidonly bit not null default 0, waiter_no_blocker bit not null default 0, wait_type varchar(60) collate latin1_general_bin2 null, wait_time decimal(18,3) null, primary key (session_id, task_address)) -- output from dbcc inputbuffer. the identity column is there to make -- it possible to add the spid later. declare @inputbuffer table (eventtype nvarchar(30) null, params int null, inputbuffer nvarchar(4000) null, ident int identity unique, spid int not null default 0 primary key) ------------------------------------------------------------------------ -- local variables. ------------------------------------------------------------------------ declare @now datetime, @ms int, @spid smallint, @rowc int, @lvl int, @dbname sysname, @dbidstr varchar(10), @stmt nvarchar(max), @request_id int, @handle varbinary(64), @stmt_start int, @stmt_end int; ------------------------------------------------------------------------ -- set up. ------------------------------------------------------------------------ -- all reads are dirty! the most important reason for this is tempdb.sys.objects. set transaction isolation level read uncommitted; set nocount on; -- processes below @minspid are system processes. select @now = getdate(); -- validate the @procdata parameter, and set default. if @procdata is null select @procdata = ''f'' if @procdata not in (''a'', ''f'') begin raiserror(''invalid value for @procdata parameter. a and f are permitted'', 16, 1) return end ------------------------------------------------------------------------ -- first capture all locks. we aggregate by type, object etc to keep -- down the volume. ------------------------------------------------------------------------ if @debug = 1 begin raiserror (''compiling lock information, time 0 ms.'', 0, 1) with nowait end; -- we force binary collation, to make the group by operation faster. with cte as ( select request_session_id, req_mode = request_mode collate latin1_general_bin2, rsc_type = resource_type collate latin1_general_bin2, rsc_subtype = resource_subtype collate latin1_general_bin2, req_status = request_status collate latin1_general_bin2, req_owner_type = request_owner_type collate latin1_general_bin2, rsc_description = case when resource_type = ''application'' then nullif(resource_description collate latin1_general_bin2, '''') end, resource_database_id, resource_associated_entity_id from sys.dm_tran_locks) insert @locks (session_id, req_mode, rsc_type, rsc_subtype, req_status, req_owner_type, rsc_description, database_id, entity_id, cnt) select request_session_id, req_mode, rsc_type, rsc_subtype, req_status, req_owner_type, rsc_description, resource_database_id, resource_associated_entity_id, count(*) from cte group by request_session_id, req_mode, rsc_type, rsc_subtype, req_status, req_owner_type, rsc_description, resource_database_id, resource_associated_entity_id ----------------------------------------------------------------------- -- get the blocking chain. ----------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''determining blocking chain, time %d ms.'', 0, 1, @ms) with nowait end -- first capture sys.dm_os_waiting_tasks, skipping non-spid tasks. the -- distinct is needed, because there may be duplicates. (i''ve seen them.) insert @dm_os_waiting_tasks (wait_session_id, wait_task, block_session_id, block_task, wait_type, wait_duration_ms) select distinct owt.session_id, owt.waiting_task_address, owt.blocking_session_id, case when owt.blocking_session_id is not null then coalesce(owt.blocking_task_address, 0x) end, owt.wait_type, owt.wait_duration_ms from sys.dm_os_waiting_tasks owt where owt.session_id is not null; ----------------------------------------------------------------------- -- get transaction. ----------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''determining active transactions, time %d ms.'', 0, 1, @ms) with nowait end ; with oldest_tran as ( select tst.session_id, tst.is_user_transaction, tat.transaction_begin_time, tat.transaction_type, tat.transaction_state, tat.dtc_state, tst.is_bound, rowno = row_number() over (partition by tst.session_id order by tat.transaction_begin_time asc) from sys.dm_tran_session_transactions tst join sys.dm_tran_active_transactions tat on tst.transaction_id = tat.transaction_id ) insert @transactions(session_id, is_user_trans, trans_start, trans_since, trans_type, trans_state, dtc_state, is_bound) select session_id, is_user_transaction, transaction_begin_time, case when datediff(day, transaction_begin_time, @now) > 20 then null else datediff(ms, transaction_begin_time, @now) / 1000.000 end, transaction_type, transaction_state, dtc_state, is_bound from oldest_tran where rowno = 1 ------------------------------------------------------------------------ -- then get the processes. we filter here for active processes once for all ------------------------------------------------------------------------ if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''collecting process information, time %d ms.'', 0, 1, @ms) with nowait end insert @procs(session_id, task_address, exec_context_id, request_id, is_user_process, current_login, orig_login, session_state, task_state, endpoint_id, proc_dbid, request_dbid, host_name, host_process_id, program_name, request_command, trancount, session_cpu, request_cpu, session_physio, request_physio, session_logreads, request_logreads, isclr, nest_level, now, login_time, last_batch, last_since, sql_handle, plan_handle, stmt_start, stmt_end, rowno) select es.session_id, coalesce(ot.task_address, 0x), coalesce(ot.exec_context_id, 0), coalesce(er.request_id, 0), es.is_user_process, coalesce(nullif(es.login_name, ''''), suser_sname(es.security_id)), coalesce(nullif(es.login_name, ''''), -- ex original_login_name suser_sname(es.security_id)), -- ex original_security_id es.status, ot.task_state, es.endpoint_id, sp.dbid, er.database_id, es.host_name, es.host_process_id, es.program_name, er.command, coalesce(er.open_transaction_count, sp.open_tran), es.cpu_time, er.cpu_time, es.reads + es.writes, er.reads + er.writes, es.logical_reads, er.logical_reads, coalesce(er.executing_managed_code, 0), er.nest_level, @now, es.login_time, es.last_request_start_time, case when datediff(day, es.last_request_start_time, @now) > 20 then null else datediff(ms, es.last_request_start_time, @now) / 1000.000 end, er.sql_handle, er.plan_handle, er.statement_start_offset, er.statement_end_offset, rowno = row_number() over (partition by es.session_id order by ot.exec_context_id, er.request_id) -- select * from sys.dm_exec_sessions es join (select spid, dbid = min(dbid), open_tran = min(open_tran) from sys.sysprocesses where ecid = 0 group by spid) as sp on sp.spid = es.session_id left join sys.dm_os_tasks ot on es.session_id = ot.session_id left join sys.dm_exec_requests er on ot.task_address = er.task_address where -- all processes requested @allprocesses > 0 -- all user sessions with a running request save ourselevs. or ot.exec_context_id is not null and es.is_user_process = 1 and es.session_id <> @@spid -- all sessions with an open transaction, even if they are idle. or sp.open_tran > 0 and es.session_id <> @@spid -- all sessions that have an interesting lock, save ourselves. or exists (select * from @locks l where l.session_id = es.session_id and l.activelock = 1) and es.session_id <> @@spid -- all sessions that is blocking someone. or exists (select * from @dm_os_waiting_tasks owt where owt.block_session_id = es.session_id) ------------------------------------------------------------------------ -- get input buffers. note that we can only find one per session, even -- a session has several requests. -- we skip this part if @@nestlevel is > 1, as presumably we are calling -- ourselves recursively from insert exec, and we may no not do another -- level of insert-exec. ------------------------------------------------------------------------ if @@nestlevel = 1 begin if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''getting input buffers, time %d ms.'', 0, 1, @ms) with nowait end declare c1 cursor fast_forward local for select distinct session_id from @procs where is_user_process = 1 open c1 while 1 = 1 begin fetch c1 into @spid if @@fetch_status <> 0 break begin try insert @inputbuffer(eventtype, params, inputbuffer) exec sp_executesql N''dbcc inputbuffer (@spid) with no_infomsgs'', N''@spid int'', @spid update @inputbuffer set spid = @spid where ident = scope_identity() end try begin catch insert @inputbuffer(inputbuffer, spid) values(''error getting inputbuffer: '' + error_message(), @spid) end catch end deallocate c1 end ----------------------------------------------------------------------- -- compute the blocking chain. ----------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''computing blocking chain, time %d ms.'', 0, 1, @ms) with nowait end -- mark blockers that are waiting, that is waiting for something else -- than another spid. update @dm_os_waiting_tasks set block_level = 0, lead_blocker_spid = a.wait_session_id from @dm_os_waiting_tasks a where a.block_session_id is null and exists (select * from @dm_os_waiting_tasks b where a.wait_session_id = b.block_session_id and a.wait_task = b.block_task) select @rowc = @@rowcount -- add an extra row for blockers that are not waiting at all. insert @dm_os_waiting_tasks (wait_session_id, wait_task, block_level, lead_blocker_spid) select distinct a.block_session_id, coalesce(a.block_task, 0x), 0, a.block_session_id from @dm_os_waiting_tasks a where not exists (select * from @dm_os_waiting_tasks b where a.block_session_id = b.wait_session_id and a.block_task = b.wait_task) and a.block_session_id is not null; select @rowc = @rowc + @@rowcount, @lvl = 0 -- then iterate as long as we find blocked processes. you may think -- that a recursive cte would be great here, but we want to exclude -- rows that has already been marked. this is difficult to do with a cte. while @rowc > 0 begin update a set block_level = b.block_level + 1, lead_blocker_spid = b.lead_blocker_spid from @dm_os_waiting_tasks a join @dm_os_waiting_tasks b on a.block_session_id = b.wait_session_id and a.block_task = b.wait_task where b.block_level = @lvl and a.block_level is null select @rowc = @@rowcount, @lvl = @lvl + 1 end -- next to find are processes that are blocked, but no one is waiting for. -- they are directly or indirectly blocked by a deadlock. they get a -- negative level initially. we clean this up later. update @dm_os_waiting_tasks set block_level = -1 from @dm_os_waiting_tasks a where a.block_level is null and a.block_session_id is not null and not exists (select * from @dm_os_waiting_tasks b where b.block_session_id = a.wait_session_id and b.block_task = a.wait_task) select @rowc = @@rowcount, @lvl = -2 -- then unwind these chains in the opposite direction to before. while @rowc > 0 begin update @dm_os_waiting_tasks set block_level = @lvl from @dm_os_waiting_tasks a where a.block_level is null and a.block_session_id is not null and not exists (select * from @dm_os_waiting_tasks b where b.block_session_id = a.wait_session_id and b.block_task = a.wait_task and b.block_level is null) select @rowc = @@rowcount, @lvl = @lvl - 1 end -- determine which blocking tasks that only block tasks within the same -- spid. update @dm_os_waiting_tasks set blocksamespidonly = 1 from @dm_os_waiting_tasks a where a.block_level is not null and a.wait_session_id = a.lead_blocker_spid and not exists (select * from @dm_os_waiting_tasks b where a.wait_session_id = b.lead_blocker_spid and a.wait_session_id <> b.wait_session_id) ----------------------------------------------------------------------- -- add block-chain and wait information to @procs. if a blockee has more -- than one blocker, we pick one. ----------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''adding blocking chain to @procs, time %d ms.'', 0, 1, @ms) with nowait end ; with block_chain as ( select wait_session_id, wait_task, block_session_id, block_task, block_level = case when block_level >= 0 then block_level else block_level - @lvl - 1 end, wait_duration_ms, wait_type, blocksamespidonly, cnt = count(*) over (partition by wait_task), rowno = row_number() over (partition by wait_task order by block_level, block_task) from @dm_os_waiting_tasks ) update p set block_level = bc.block_level, block_session_id = bc.block_session_id, block_exec_context_id = coalesce(p2.exec_context_id, -1), block_request_id = coalesce(p2.request_id, -1), blockercnt = bc.cnt, blocksamespidonly = bc.blocksamespidonly, wait_time = convert(decimal(18, 3), bc.wait_duration_ms) / 1000, wait_type = bc.wait_type from @procs p join block_chain bc on p.session_id = bc.wait_session_id and p.task_address = bc.wait_task and bc.rowno = 1 left join @procs p2 on bc.block_session_id = p2.session_id and bc.block_task = p2.task_address -------------------------------------------------------------------- -- delete "uninteresting" locks from @locks for processes not in @procs. -------------------------------------------------------------------- if @allprocesses = 0 begin if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''deleting uninteresting locks, time %d ms.'', 0, 1, @ms) with nowait end delete @locks from @locks l where (activelock = 0 or session_id = @@spid) and not exists (select * from @procs p where p.session_id = l.session_id) end ----------------------------------------------------------------------- -- get object names from ids in @procs and @locks. you may think that -- we could use object_name and its second database parameter, but -- object_name takes out a sch-s lock (even with read uncommitted) and -- gets blocked if a object (read temp table) has been created in a transaction. ----------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''getting object names, time %d ms.'', 0, 1, @ms) with nowait end -- first get all entity ids into the temp table. we can translate -- object ids now. and we save the database name as a fallback for -- those where do not translate more. yes, we save the entity id twice. insert #objects (idtype, database_id, entity_id, hobt_id) select distinct case when rsc_type = ''object'' then ''obj'' when rsc_type in (''page'', ''key'', ''rid'', ''hobt'') then ''hobt'' when rsc_type = ''allocation_unit'' then ''au'' else ''misc'' end, database_id, entity_id, entity_id from @locks where rsc_type in (''page'', ''key'', ''rid'', ''hobt'', ''allocation_unit'', ''object'') union select distinct ''obj'', curdbid, curobjid, curobjid from @procs where curdbid is not null and curobjid is not null declare c2 cursor static local for select distinct str(database_id), quotename(db_name(database_id)) from #objects where idtype in (''obj'', ''hobt'', ''au'') option (keepfixed plan) open c2 while 1 = 1 begin fetch c2 into @dbidstr, @dbname if @@fetch_status <> 0 break -- first handle allocation units. they bring us a hobt_id, or we go -- directly to the object when the container is a partition_id. we -- always get the type_desc. to make the dynamic sql easier to read, -- we use some placeholders. select @stmt = '' update #objects set type_desc = au.type_desc, hobt_id = case when au.type in (1, 3) then au.container_id end, idtype = case when au.type in (1, 3) then "hobt" else "au" end, object_name = case when au.type = 2 then db_name(@dbidstr) + "." + s.name + "." + o.name + case when p.index_id <= 1 then "" else "." + i.name end + case when p.partition_number > 1 then "(" + ltrim(str(p.partition_number)) + ")" else "" end when au.type = 0 then db_name(@dbidstr) + " (dropped table et al)" end from #objects ob join @dbname.sys.allocation_units au on ob.entity_id = au.allocation_unit_id -- we should only go all the way from sys.partitions, for type = 3. left join (@dbname.sys.partitions p join @dbname.sys.objects o on p.object_id = o.object_id join @dbname.sys.indexes i on p.object_id = i.object_id and p.index_id = i.index_id join @dbname.sys.schemas s on o.schema_id = s.schema_id) on au.container_id = p.partition_id and au.type = 2 where ob.database_id = @dbidstr and ob.idtype = "au" option (keepfixed plan); '' -- now we can translate all hobt_id, including those we got from the -- allocation units. select @stmt = @stmt + '' update #objects set object_name = db_name(@dbidstr) + "." + s.name + "." + o.name + case when p.index_id <= 1 then "" else "." + i.name end + case when p.partition_number > 1 then "(" + ltrim(str(p.partition_number)) + ")" else "" end + coalesce(" (" + ob.type_desc + ")", "") from #objects ob join @dbname.sys.partitions p on ob.hobt_id = p.hobt_id join @dbname.sys.objects o on p.object_id = o.object_id join @dbname.sys.indexes i on p.object_id = i.object_id and p.index_id = i.index_id join @dbname.sys.schemas s on o.schema_id = s.schema_id where ob.database_id = @dbidstr and ob.idtype = "hobt" option (keepfixed plan) '' -- and now object ids, idtype = obj. select @stmt = @stmt + '' update #objects set object_name = db_name(@dbidstr) + "." + coalesce(s.name + "." + o.name, "<" + ltrim(str(ob.entity_id)) + ">") from #objects ob left join (@dbname.sys.objects o join @dbname.sys.schemas s on o.schema_id = s.schema_id) on convert(int, ob.entity_id) = o.object_id where ob.database_id = @dbidstr and ob.idtype = "obj" option (keepfixed plan) '' -- fix the placeholders. select @stmt = replace(replace(replace(@stmt, ''"'', ''''''''), ''@dbname'', @dbname), ''@dbidstr'', @dbidstr) -- and run the beast. --print @stmt exec (@stmt) end deallocate c2 ---------------------------------------------------------------------- -- get the query text. this is not done in the main query, as we could -- be blocked if someone is creating an sp and executes it in a -- transaction. ---------------------------------------------------------------------- if @@nestlevel = 1 begin if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''retrieving current statement, time %d ms.'', 0, 1, @ms) with nowait end -- set lock timeout to avoid being blocked. set lock_timeout 5 -- first try to get all query plans in one go. begin try update @procs set curdbid = est.dbid, curobjid = est.objectid, current_stmt = case when est.encrypted = 1 then ''-- encrypted, pos '' + ltrim(str((p.stmt_start + 2)/2)) + '' - '' + ltrim(str((p.stmt_end + 2)/2)) when p.stmt_start >= 0 then substring(est.text, (p.stmt_start + 2)/2, case p.stmt_end when -1 then datalength(est.text) else (p.stmt_end - p.stmt_start + 2) / 2 end) end from @procs p cross apply sys.dm_exec_sql_text(p.sql_handle) est end try begin catch -- if this fails, try to get the texts one by one. declare text_cur cursor static local for select distinct session_id, request_id, sql_handle, stmt_start, stmt_end from @procs where sql_handle is not null open text_cur while 1 = 1 begin fetch text_cur into @spid, @request_id, @handle, @stmt_start, @stmt_end if @@fetch_status <> 0 break begin try update @procs set curdbid = est.dbid, curobjid = est.objectid, current_stmt = case when est.encrypted = 1 then ''-- encrypted, pos '' + ltrim(str((p.stmt_start + 2)/2)) + '' - '' + ltrim(str((p.stmt_end + 2)/2)) when p.stmt_start >= 0 then substring(est.text, (p.stmt_start + 2)/2, case p.stmt_end when -1 then datalength(est.text) else (p.stmt_end - p.stmt_start + 2) / 2 end) end from @procs p cross apply sys.dm_exec_sql_text(p.sql_handle) est where p.session_id = @spid and p.request_id = @request_id end try begin catch update @procs set current_stmt = ''error: *** '' + error_message() + '' ***'' where session_id = @spid and request_id = @request_id end catch end deallocate text_cur end catch set lock_timeout 0 end -------------------------------------------------------------------- -- get query plans. the difficult part is that the convert to xml may -- fail if the plan is too deep. therefore we catch this error, and -- resort to a cursor in this case. since query plans are not included -- in text mode, we skip if @nestlevel is > 1. -------------------------------------------------------------------- if @@nestlevel = 1 begin if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''retrieving query plans, time %d ms.'', 0, 1, @ms) with nowait end -- adam says that getting the query plans can time out too... set lock_timeout 5 begin try update @procs set current_plan = convert(xml, etqp.query_plan) from @procs p outer apply sys.dm_exec_text_query_plan( p.plan_handle, p.stmt_start, p.stmt_end) etqp where p.plan_handle is not null end try begin catch declare plan_cur cursor static local for select distinct session_id, request_id, plan_handle, stmt_start, stmt_end from @procs where plan_handle is not null open plan_cur while 1 = 1 begin fetch plan_cur into @spid, @request_id, @handle, @stmt_start, @stmt_end if @@fetch_status <> 0 break begin try update @procs set current_plan = (select convert(xml, etqp.query_plan) from sys.dm_exec_text_query_plan( @handle, @stmt_start, @stmt_end) etqp) from @procs p where p.session_id = @spid and p.request_id = @request_id end try begin catch update @procs set current_plan = (select ''could not get query plan'' as [@alert], error_number() as [@errno], error_severity() as [@level], error_message() as [@errmsg] for xml path(''error'')) where session_id = @spid and request_id = @request_id end catch end deallocate plan_cur end catch set lock_timeout 0 -- there is a bug in dm_exec_text_query_plan which causes the attribute -- statementtext to include the full text of the batch up to current -- statement. this causes bloat in ssms. whence we fix the attribute. ; with xmlnamespaces( ''http://schemas.microsoft.com/sqlserver/2004/07/showplan'' as sp) update @procs set current_plan.modify('' replace value of ( /sp:showplanxml/sp:batchsequence/sp:batch/ sp:statements/sp:stmtsimple/@statementtext)[1] with substring((/sp:showplanxml/sp:batchsequence/sp:batch/ sp:statements/sp:stmtsimple/@statementtext)[1], (sql:column("stmt_start") + 2) div 2) '') where current_plan is not null and stmt_start is not null end -------------------------------------------------------------------- -- if user has selected to see process data only on the first row, -- we should number the rows in @locks. -------------------------------------------------------------------- if @procdata = ''f'' begin if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''determining first row, time %d ms.'', 0, 1, @ms) with nowait end update @locks set rowno = b.rowno from @locks a join (select l.ident, rowno = row_number() over(partition by l.session_id order by case l.req_status when ''grant'' then ''zzzz'' else l.req_status end, o.object_name, l.rsc_type, l.rsc_description) from @locks l left join #objects o on l.database_id = o.database_id and l.entity_id = o.entity_id) as b on a.ident = b.ident option (keepfixed plan) end --------------------------------------------------------------------- -- before we can join in the locks, we need to make sure that all -- processes with a running request has a row with exec_context_id = -- request_id = 0. (those without already has such a row.) --------------------------------------------------------------------- if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''supplementing @procs, time %d ms.'', 0, 1, @ms) with nowait end insert @procs(session_id, task_address, exec_context_id, request_id, is_user_process, orig_login, current_login, session_state, endpoint_id, trancount, proc_dbid, host_name, host_process_id, program_name, session_cpu, session_physio, session_logreads, now, login_time, last_batch, last_since, rowno) select session_id, 0x, 0, 0, is_user_process, orig_login, current_login, session_state, endpoint_id, 0, proc_dbid, host_name, host_process_id, program_name, session_cpu, session_physio, session_logreads, now, login_time, last_batch, last_since, 0 from @procs a where a.rowno = 1 and not exists (select * from @procs b where b.session_id = a.session_id and b.exec_context_id = 0 and b.request_id = 0) -- a process may be waiting for a lock according sys.dm_os_tran_locks, -- but it was not in sys.dm_os_waiting_tasks. let''s mark this up. update @procs set waiter_no_blocker = 1 from @procs p where exists (select * from @locks l where l.req_status = ''wait'' and l.session_id = p.session_id and not exists (select * from @procs p2 where p.session_id = l.session_id)) ------------------------------------------------------------------------ -- for plain results we are ready to return now. ------------------------------------------------------------------------ if @debug = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''returning result set, time %d ms.'', 0, 1, @ms) with nowait end -- note that the query is a full join, since @locks and @procs may not -- be in sync. processes may have gone away, or be active without any -- locks. as for the transactions, we team up with the processes. select readed_at = getdate(), spid = coalesce(p.spidstr, ltrim(str(l.session_id))), command = case when coalesce(p.exec_context_id, 0) = 0 and coalesce(l.rowno, 1) = 1 then p.request_command else '''' end, login = case when coalesce(p.exec_context_id, 0) = 0 and coalesce(l.rowno, 1) = 1 then case when p.is_user_process = 0 then ''system process'' else p.orig_login + case when p.current_login <> p.orig_login or p.orig_login is null then '' ('' + p.current_login + '')'' else '''' end end else '''' end, host = case when coalesce(p.exec_context_id, 0)= 0 and coalesce(l.rowno, 1) = 1 then p.host_name else '''' end, appl = case when coalesce(p.exec_context_id, 0) = 0 and coalesce(l.rowno, 1) = 1 then p.program_name else '''' end, dbname = case when coalesce(l.rowno, 1) = 1 and coalesce(p.exec_context_id, 0) = 0 then coalesce(db_name(p.request_dbid), db_name(p.proc_dbid)) else '''' end, prcstatus = case when coalesce(l.rowno, 1) = 1 then coalesce(p.task_state, p.session_state) else '''' end, spid_ = p.spidstr, opntrn = case when p.exec_context_id = 0 then coalesce(ltrim(str(nullif(p.trancount, 0))), '''') else '''' end, trninfo = case when coalesce(l.rowno, 1) = 1 and p.exec_context_id = 0 and t.is_user_trans is not null then case t.is_user_trans when 1 then ''u'' else ''s'' end + ''-'' + case t.trans_type when 1 then ''rw'' when 2 then ''r'' when 3 then ''sys'' when 4 then ''dist'' else ltrim(str(t.trans_type)) end + ''-'' + ltrim(str(t.trans_state)) + case t.dtc_state when 0 then '''' else ''-'' end + case t.dtc_state when 0 then '''' when 1 then ''dtc:active'' when 2 then ''dtc:prepared'' when 3 then ''dtc:commited'' when 4 then ''dtc:aborted'' when 5 then ''dtc:recovered'' else ''dtc:'' + ltrim(str(t.dtc_state)) end + case t.is_bound when 0 then '''' when 1 then ''-bnd'' end else '''' end, blklvl = case when p.block_level is not null then case p.blocksamespidonly when 1 then ''('' else '''' end + case when p.block_level = 0 then ''!!'' else ltrim(str(p.block_level)) end + case p.blocksamespidonly when 1 then '')'' else '''' end -- if the process is blocked, but we do not -- have a block level, the process is in a -- dead lock. when p.block_session_id is not null then ''dd'' when p.waiter_no_blocker = 1 then ''??'' else '''' end, blkby = coalesce(p.block_spidstr, ''''), cnt = case when p.exec_context_id = 0 and p.request_id = 0 then coalesce(ltrim(str(l.cnt)), ''0'') else '''' end, object = case l.rsc_type when ''application'' then coalesce(db_name(l.database_id) + ''|'', '''') + l.rsc_description else coalesce(o2.object_name, db_name(l.database_id), '''') end, rsctype = coalesce(l.rsc_type, ''''), locktype = coalesce(l.req_mode, ''''), lstatus = case l.req_status when ''grant'' then lower(l.req_status) else coalesce(l.req_status, '''') end, ownertype = case l.req_owner_type when ''shared_transaction_workspace'' then ''stw'' else coalesce(l.req_owner_type, '''') end, rscsubtype = coalesce(l.rsc_subtype, ''''), waittime = case when coalesce(l.rowno, 1) = 1 then coalesce(ltrim(str(p.wait_time, 18, 3)), '''') else '''' end, waittype = case when coalesce(l.rowno, 1) = 1 then coalesce(p.wait_type, '''') else '''' end, spid__ = p.spidstr, cpu = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then coalesce(ltrim(str(p.session_cpu)), '''') + case when p.request_cpu is not null then '' ('' + ltrim(str(p.request_cpu)) + '')'' else '''' end else '''' end, physio = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then coalesce(ltrim(str(p.session_physio, 18)), '''') + case when p.request_physio is not null then '' ('' + ltrim(str(p.request_physio)) + '')'' else '''' end else '''' end, logreads = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then coalesce(ltrim(str(p.session_logreads, 18)), '''') + case when p.request_logreads is not null then '' ('' + ltrim(str(p.request_logreads)) + '')'' else '''' end else '''' end, now = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then convert(char(12), p.now, 114) else '''' end, login_time = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then case datediff(day, p.login_time, @now) when 0 then convert(varchar(8), p.login_time, 8) else convert(char(7), p.login_time, 12) + convert(varchar(8), p.login_time, 8) end else '''' end, last_batch = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then case datediff(day, p.last_batch, @now) when 0 then convert(varchar(8), p.last_batch, 8) else convert(char(7), p.last_batch, 12) + convert(varchar(8), p.last_batch, 8) end else '''' end, trn_start = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 and t.trans_start is not null then case datediff(day, t.trans_start, @now) when 0 then convert(varchar(8), t.trans_start, 8) else convert(char(7), t.trans_start, 12) + convert(varchar(8), t.trans_start, 8) end else '''' end, last_since = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then str(p.last_since, 11, 3) else '''' end, trn_since = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 and t.trans_since is not null then str(t.trans_since, 11, 3) else '''' end, clr = case when p.exec_context_id = 0 and p.isclr = 1 then ''clr'' else '''' end, nstlvl = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then coalesce(ltrim(str(p.nest_level)), '''') else '''' end, spid___ = p.spidstr, inputbuffer = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then coalesce(i.inputbuffer, '''') else '''' end, current_sp = coalesce(o1.object_name, ''''), curstmt = case when coalesce(l.rowno, 1) = 1 then coalesce(p.current_stmt, '''') else coalesce(substring( p.current_stmt, 1, 50), '''') end, current_plan = case when p.exec_context_id = 0 and coalesce(l.rowno, 1) = 1 then p.current_plan end, hostprc = case when coalesce(p.exec_context_id, 0) = 0 and coalesce(l.rowno, 1) = 1 then ltrim(str(p.host_process_id)) else '''' end, endpoint = case when coalesce(p.exec_context_id, 0) = 0 and coalesce(l.rowno, 1) = 1 then e.name else '''' end from @procs p left join #objects o1 on p.curdbid = o1.database_id and p.curobjid = o1.entity_id left join @inputbuffer i on p.session_id = i.spid and p.exec_context_id = 0 left join sys.endpoints e on p.endpoint_id = e.endpoint_id left join @transactions t on t.session_id = p.session_id full join (@locks l left join #objects o2 on l.database_id = o2.database_id and l.entity_id = o2.entity_id) on p.session_id = l.session_id and p.exec_context_id = 0 and p.request_id = 0 where db_name() = case when coalesce(l.rowno, 1) = 1 and coalesce(p.exec_context_id, 0) = 0 then coalesce(db_name(p.request_dbid), db_name(p.proc_dbid)) else '''' end order by coalesce(p.session_id, l.session_id), p.exec_context_id, coalesce(nullif(p.request_id, 0), 99999999), l.rowno, lstatus, coalesce(o2.object_name, db_name(l.database_id)), l.rsc_type, l.rsc_description option (keepfixed plan) if @debug = 1 and @@nestlevel = 1 begin select @ms = datediff(ms, @now, getdate()) raiserror (''completed, time %d ms.'', 0, 1, @ms) with nowait end if object_id(''sp__lock_help'') is null exec sp__printf ''-- missing "sp__lock_help"'' else exec sp__lock_help goto ret ret: return @ret end -- sp__lock_ex' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__lock_ex: -- =============================================================== sp__lock_help select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__lock_help',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120905 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__lock_help') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__lock_help') with nowait goto skip_sp__lock_help end if @ver>120905 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__lock_help') with nowait goto skip_sp__lock_help end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__lock_help') with nowait if exists( select top 1 null from sys.objects where name='sp__lock_help' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__lock_help] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:process,status v:120905\s.zaglio: called by sp__lock and sp__lock_ex */ create proc sp__lock_help @opt sysname=null as begin set nocount on print '' --- See also --- sp__lock_ex show grouped and detailed info sp__perf show most heavy running processes --- Legend --- Campi visualizzati: blocking SPID del processo che viene bloccato da quello di riga n_locks conto totale dei lock ad opera dello SPID di riga Process status: dormant = SQL Server is resetting the session. running = The session is running one or more batches. When Multiple Active Result Sets (MARS) is enabled, a session can run multiple batches. For more information, see Using Multiple Active Result Sets (MARS). background = The session is running a background task, such as deadlock detection. rollback = The session has a transaction rollback in process. pending = The session is waiting for a worker thread to become available. runnable = The task in the session is in the runnable queue of a scheduler while waiting to get a time quantum. spinloop = The task in the session is waiting for a spinlock to become free. suspended = The session is waiting for an event, such as I/O, to complete. Tipo di blocco: RID = Blocco su una sola riga di una tabella identificata da un identificatore di riga (RID). KEY = Blocco all''''interno di un indice che protegge un intervallo di chiavi in transazioni serializzabili. PAG = Blocco su una pagina di dati o di indice. EXT = Blocco su un extent, un''''unità di 8 pagine contigue. TAB = Blocco su un''''intera tabella, inclusi tutti i dati e gli indici. DB = Blocco su un database. FIL = Blocco su un file di database. APP = Blocco su una risorsa specifica di un''''applicazione. MD = Blocco su metadati o informazioni del catalogo. HBT = Blocco su un heap o un indice b-tree. Queste informazioni non sono complete in SQL Server 2005. AU = Blocco su un''''unità di allocazione. Queste informazioni non sono complete in SQL Server 2005. Modalità di blocco richiesta. I possibili valori sono i seguenti: NULL = Non è concesso l''''accesso alla risorsa. Funge da segnaposto. Sch-S = Stabilità dello schema. Garantisce che nessun elemento dello schema, ad esempio una tabella o un indice, venga eliminato mentre in una sessione viene mantenuto attivo un blocco di stabilità dello schema sull''''elemento dello schema. Sch-M = Modifica dello schema. Deve essere impostato in tutte le sessioni in cui si desidera modificare lo schema della risorsa specificata. Assicura che nessun''''altra sessione faccia riferimento all''''oggetto specificato. S = Condiviso. La sessione attiva dispone dell''''accesso condiviso alla risorsa. U = Aggiornamento. Indica un blocco di aggiornamento acquisito su risorse che potrebbero venire aggiornate. Viene utilizzato per evitare una forma comune di deadlock che si verifica quando in più sessioni vengono bloccate risorse che potrebbero venire aggiornate in un momento successivo. X = Esclusivo. La sessione dispone dell''''accesso esclusivo alla risorsa. IS = Preventivo condiviso. Indica l''''intenzione di impostare blocchi condivisi (S) su alcune risorse subordinate nella gerarchia dei blocchi. IU = Preventivo aggiornamento. Indica l''''intenzione di impostare blocchi di aggiornamento (U) su alcune risorse subordinate nella gerarchia dei blocchi. IX = Preventivo esclusivo. Indica l''''intenzione di impostare blocchi esclusivi (X) su alcune risorse subordinate nella gerarchia dei blocchi. SIU = Condiviso preventivo aggiornamento. Indica l''''accesso condiviso a una risorsa con l''''intenzione di acquisire blocchi di aggiornamento su risorse subordinate nella gerarchia dei blocchi. SIX = Condiviso preventivo esclusivo. Indica l''''accesso condiviso a una risorsa con l''''intenzione di acquisire blocchi esclusivi su risorse subordinate nella gerarchia dei blocchi. UIX = Aggiornamento preventivo esclusivo. Indica un blocco di aggiornamento attivato su una risorsa con l''''intenzione di acquisire blocchi esclusivi su risorse subordinate nella gerarchia dei blocchi. BU = Aggiornamento di massa. Utilizzato dalle operazioni di massa. RangeS_S = Blocco condiviso intervalli di chiavi e risorsa. Indica una scansione di intervallo serializzabile. RangeS_U = Blocco condiviso intervalli di chiavi e aggiornamento risorsa. Indica una scansione di aggiornamento serializzabile. RangeI_N = Blocco inserimento intervalli di chiavi e risorsa Null. Utilizzato per verificare gli intervalli prima di inserire una nuova chiave in un indice. RangeI_S = Blocco conversione intervalli di chiavi. Creato da una sovrapposizione dei blocchi RangeI_N e S. RangeI_U = Blocco conversione intervallo di chiavi creato da una sovrapposizione di blocchi RangeI_N e U. RangeI_X = Blocco conversione intervallo di chiavi creato da una sovrapposizione di blocchi RangeI_N e X. RangeX_S = Blocco conversione intervallo di chiavi creato da una sovrapposizione di blocchi RangeI_N e RangeS_S. RangeX_U = Blocco conversione intervallo di chiavi creato da una sovrapposizione di blocchi RangeI_N e RangeS_U. RangeX_X = Blocco esclusivo intervalli di chiavi e risorsa. Si tratta di un blocco di conversione utilizzato quando viene aggiornata una chiave in un intervallo. Stato della richiesta di blocco: CNVRT: è in corso la conversione del blocco da un''''altra modalità, ma la conversione è bloccata da un altro processo che mantiene attivo un blocco con una modalità in conflitto. GRANT: il blocco è stato ottenuto. WAIT: il blocco è bloccato da un altro processo che mantiene attivo un blocco con una modalità in conflitto. '' end -- sp__lock_help' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__lock_help: -- ===================================================================== sp__log select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__log',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131014 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__log') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__log') with nowait goto skip_sp__log end if @ver>131014 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__log') with nowait goto skip_sp__log end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__log') with nowait if exists( select top 1 null from sys.objects where name='sp__log' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__log] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,log v:131014\s.zaglio: d tag into o v:120926\s.zaglio: autogenerate of log table v:110510\s.zaglio: modified idx names into %__% r:110422\s.zaglio: test with md5 r:110421\s.zaglio: generalized log table v:110316\s.zaglio: changed @txt to ntext v:110213\s.zaglio: added macro %host_name% v:110208\s.zaglio: added update v:100919.1105\s.zaglio: adapted to be used for generic I/O proc v:100919\s.zaglio: removed a dbg info v:100314\s.zaglio: fast&smart new log o:100314\s.zaglio: sp__trace t:sp__log #create_table# t: exec sp__log ''test'' exec sp__log ''test sub (%s) log'',''test'',@n=10,@p1=''xx'' t: declare @rid int exec sp__log @rid=''test'',@id=@rid out exec sp__log ''test sub log 1'',@rid select top 10 * from [log] order by id desc t: sp__log_show ''%'' t: drop table log */ CREATE proc sp__log @txt nvarchar(4000) =null, @ref sysname =null, @n money =null, @m money =null, @id int =null out, @pid int =null, @p1 sql_variant =null, @p2 sql_variant =null, @p3 sql_variant =null, @p4 sql_variant =null, @opt sysname =null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if object_id(''log'',''U'') is null begin exec sp__printf ''-- autogenerate log table'' exec('' create table log( id int identity, rid int null, -- refer to parent pid int null, -- refer to extarnal item [key] as substring(c1,1,256), -- guid or tbl.fld c1 varbinary(8000) null, -- txt or msg c2 varbinary(256) null, -- spid c3 varbinary(256) null, -- n or table c4 varbinary(256) null, -- m or field dt datetime not null ) alter table dbo.[log] add constraint pk__log primary key (id desc) create index ix__log_rid on [log](rid,id) -- drop index [log].ix__log_rid create index ix__log_key on [log]([key]) -- drop index [log].ix__log_key create index ix__log_dt on [log](dt desc) -- drop index [log].ix__log_dt '') end if @txt is null and @ref is null and @id is null goto help declare @log nvarchar(4000),@vb_log varbinary(8000), @chk bit select @log=substring(@txt,1,4000), @chk =charindex(''|chk|'',@opt) declare @rid int,@st sysname if not @log is null begin select @log=replace(@log,''@@host_name'',host_name()) select @log=replace(@log,''@@system_user'',system_user) select @st=convert(sysname,@@trancount) select @log=replace(@log,''@@trancount'',@st) end if not @p1 is null select @log=dbo.fn__printf(@log,@p1,@p2,@p3,@p4, null,null,null,null,null,null) -- get binary version select @vb_log=cast(@log as varbinary(8000)) -- if a reference is specified ... if not @ref is null begin if isnumeric(@ref)=1 select @rid=convert(int,@ref) else begin -- ... find the id and ... select top 1 @rid=id from [log] with (nolock) where c1=@ref order by id desc -- ... if not exists, add it if @rid is null exec sp__log @ref,@id=@rid out end end -- get@rid -- example: sp__log @ref=''test'',@id=@rid out -- if nothing to log but @ref, return the id if @log is null and not @ref is null begin select @id=@rid goto ret end -- example: sp__log @hash,@ref=test,@id=@id out,@opt=chk -- if CHK option, verify if already exists @log or @ref if @chk=1 and not @log is null and not @rid is null begin if exists(select null from [log] with (nolock) where [key]=substring(@vb_log,1,256) and rid=@rid ) begin select @id=null goto ret end end -- chk -- example: sp__log ''sub log info 1 chg'',''test'',@id=@id -- not null id -- ================================================================== act_upd == if not @id is null update [log] set pid=isnull(@pid,pid), c1=isnull(@vb_log,c1), c3=isnull(@n,c3), c4=isnull(@m,c4) where id=@id -- example: sp__log ''test'',@id=@rid out -- examples: sp__log ''sub log info 1'',''test'', @id=@id out -- id must be null -- ================================================================== act_ins == if @id is null begin if @log!=''#src'' -- single log begin insert [log]( rid, pid, c1, c2, c3, c4, dt) select @rid, @pid, @vb_log as c1, @@spid, @n, @m, getdate() select @id=@@identity end else begin -- log from table #src if @rid is null goto err_src insert [log]( rid, pid, c1, c2, c3, c4, dt) select @rid, @pid, cast(src.line as varbinary(8000)) as c1, @@spid, @n, @m, getdate() from #src src order by lno end end -- if @id is null -- exec sp__printf ''rid:%s ref:%s'',@rid,@ref goto ret -- =================================================================== errors == err_src: exec @ret=sp__err ''#src insert require a reference'' goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope register info into table "log" Parameters @txt text to log Some macros are replaced: %s,%d with @p1,@p2,@p3,@p4 @@host_name, @@system_user, @@trancount with replative mssql functions if #src, copy line by line the #src content (@ref is required) @ref is used for children of previous returned @id (if is a string, search the relative id) @id if null, return the new id (used then as @ref) if not null, update the relative record (normally one of @n,@m field) @opt options chk if @ref and @txt already exists, null the @id Notes This sp require the "log" table Examples exec sp__log "fast raw log" -- structured log declare @id int, @rid int exec sp__log "test",@id=@rid out -- ins select "ref id="+cast(@rid as sysname) exec sp__log "sub log info 1","test", @id=@id out -- attach 1 by ref and get id exec sp__log @ref="test",@id=@rid out -- get ref id exec sp__log "sub log info 2'''',@rid -- attach 2 by rid exec sp__log "%d , %s", @rid, @p1=12, @p2="XX" -- parametrized exec sp__log "sub log info 1 chg","test",@id=@id -- upd -- show last 10 logs exec sp__log_view #10 -- store content of #src (run 2 times) declare @id int, @hash binary(16) create table #src(lno int identity,line nvarchar(4000)) insert #src(line) select top 3 [name] from sysobjects order by id exec sp__md5 @hash out exec sp__log @hash,@ref=test,@id=@id out,@opt=chk if not @id is null begin exec sp__log #src,@ref=@id exec sp__log_view #10 -- show last 10 logs exec sp__log_view @hash,test -- show specific log end else print "already_stored" drop table #src '' ret: return @ret end -- sp__log' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__log: -- =============================================================== sp__log_trace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__log_trace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130605 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__log_trace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__log_trace') with nowait goto skip_sp__log_trace end if @ver>130605 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__log_trace') with nowait goto skip_sp__log_trace end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__log_trace') with nowait if exists( select top 1 null from sys.objects where name='sp__log_trace' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__log_trace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130605\s.zaglio: removed printf deprecated parameters v:110314\s.zaglio: renamed from deprecated sp__trace; use sp__log v:100205\s.zaglio: deprecated fn__injectN to fn__inject and added help v:090603\S.Zaglio: added @elapsed and %e v:090131\S.Zaglio: removed replace if @p? are all null v:090129\S.Zaglio: added @privacy v:090128\S.Zaglio: forced on @print to match correclty when error and replaced | with , in params v:090121\S.Zaglio: added outbuffer trace when @txt=''sp__outbuffer'' v:090117\S.Zaglio: added @force to sp_prinftf v:081223\S.Zaglio: added multilevel @dbg v:081215\S.Zaglio: a bug when print. Date style to 126 v:081203\S.Zaglio: added @print, removed @trace from sp__printf v:081129\S.Zaglio: set erf_id as relative to simplify export to other server v:081120\S.Zaglio: added @last_id and @ref_id and @proc. Old compatible and auto add new log_trace col v:081030\S.Zaglio: convert in nvarchar (be careful with 4000 chars and '' inside) v:081014\S.Zaglio: added %t as replacer for iso date v:080925\S.Zaglio: added privacy v:080922\S.Zaglio: added @txt as numeric of @@error, replaced with sysmessages v:080918\S.Zaglio: added @trace_once out to simplify loop tracing (run only once) v:080628\S.Zaglio: fast log for debugging t: begin declare @txt nvarchar(4000) set @txt=''12345''+space(3800)+'' after 3800 spaces:67890''+space(85)+''abcdefghi'' exec sp__trace ''first run fs'',@init=1 exec sp__trace @txt,@proc=''sp_hello'' exec sp__trace ''add %s'',''element'' exec sp__trace ''added %d'',12 -- test long comments select dbo.fn__str_simplify(txt,default) as txt from log_trace where len(txt)>1000 exec sp__trace -- print exec sp__trace ''second run fs'',@init=1 exec sp__trace ''add %s'',''element'' exec sp__trace ''added ''''%d'''''',12 exec sp__trace -- print exec sp__trace @clean=1 -- printf test/debugging exec sp__trace ''printf test'',@init=1 exec sp__trace ''im here'',@print=1 exec sp__trace -- print exec sp__trace @clean=1 select dbo.fn__str_simplify(txt,default) as txt from log_trace where len(txt)>1000 end t: sp__trace ''select x from opendatasource(datas,uid,password=xyz) where ...'' select * from log_trace where id=(select max(id) from log_trace) t: -- test @ref_id,@last_id,@proc features begin truncate table log_trace declare @ref_id int exec sp__trace ''test for old compatibuility'',@clean=1 exec sp__trace ''parent'',@last_id=@ref_id out exec sp__trace ''child1'',@ref_id=@ref_id exec sp__trace ''child2'',@ref_id=@ref_id exec sp__trace ''this is a new feature'',@proc=''mySP'' exec sp__trace exec sp__trace @clean=1 end */ CREATE proc [dbo].[sp__log_trace] @txt nvarchar(4000)=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @p5 sql_variant=null, @p6 sql_variant=null, @p7 sql_variant=null, @p8 sql_variant=null, @init bit=0, @clean bit=0, @trace bit=1, -- spare to write on each call: if @trace=1 exec sp__trace ... @trace_once bit=1 out, -- spare to write on each call: if @trace=1 exec sp__trace ... @last_id int=null out, -- return last @@identity @ref_id int=null, @proc sysname=null, -- short cut to %t|@proc|@txt format @print bit=0, @privacy bit=0, @elapsed datetime=null out, @dbg smallint=0 as begin declare @now datetime declare @ms int if not @elapsed is null begin set @now=getdate() set @ms=datediff(ms,@elapsed,@now) set @txt=replace(@txt,''%e'',convert(nvarchar(48),@ms)) set @elapsed=@now end declare @sql nvarchar(4000) declare @sql1 nvarchar(4000) if @txt=''sp__outbuffer'' begin set @txt='''' exec sp__outputbuffer @txt out end if @dbg<0 begin exec sp__printf ''@@nestlevel=%d'',@@nestlevel end set nocount on if isnumeric(@txt)=1 begin if exists(select top 1 error from master.dbo.sysmessages where error=convert(int,@txt)) select top 1 @txt=description from master.dbo.sysmessages where error=convert(int,@txt) end if @init=1 or @clean=1 begin if dbo.fn__exists(''log_trace'',''U'')=0 begin set @sql=''create table log_trace (id int identity, ref_id int, spid int, txt nvarchar(4000))'' exec sp__printf ''-- log_trace created'' exec(@sql) end -- create else begin if @proc is null set @sql=''delete from log_trace where spid=''+convert(nvarchar(32),@@spid) else set @sql=''delete from log_trace where dbo.fn__str_at(txt,''''|'''',2)=''+@proc exec(@sql) end if @txt is null goto ret end -- @init=1 if @txt is null and @clean=0 goto help if not @proc is null set @txt=''%t|''+@proc+''|''+left(@txt,4000-20-len(@proc)) set @txt=replace(@txt,''%t'',convert(nvarchar(48),getdate(),126)) if not @p1 is null or not @p2 is null or not @p3 is null or not @p4 is null or not @p5 is null or not @p6 is null or not @p7 is null or not @p8 is null begin set @p1=replace(convert(nvarchar(4000),@p1),''|'','','') set @p2=replace(convert(nvarchar(4000),@p2),''|'','','') set @p3=replace(convert(nvarchar(4000),@p3),''|'','','') set @p4=replace(convert(nvarchar(4000),@p4),''|'','','') set @p5=replace(convert(nvarchar(4000),@p5),''|'','','') set @p6=replace(convert(nvarchar(4000),@p6),''|'','','') set @p7=replace(convert(nvarchar(4000),@p7),''|'','','') set @p8=replace(convert(nvarchar(4000),@p8),''|'','','') set @txt=dbo.fn__printf(@txt,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,null,null) end if left(ltrim(@txt),7) in (''select '',''insert '',''delete '',''update '',''execute'',''exec @r'') set @txt=dbo.fn__str_simplify(@txt,default) if @privacy=1 begin if @txt like ''%OPENDATASOURCE%(%password%)%'' begin -- kepp privacy declare @i int,@j int set @i=charindex(''opendatasource'',@txt) if @i>0 set @i=charindex(''('',@txt,@i) set @j=charindex('')'',@txt,@i) if @j<1 set @j=len(@txt) if @i>0 set @txt=substring(@txt,1,@i)+''***privacy***''+substring(@txt,@j,len(@txt)) end end -- privacy if @print=1 begin if coalesce(@proc,'''')='''' set @sql=@txt else set @sql=dbo.fn__str_at(@txt,''|'',3) exec sp__printf @sql end if @trace=0 or @trace_once=0 goto ret set @trace_once=0 -- disable trace in loop (the caller must use out to enable this) if @ref_id is null begin set @sql=''insert into log_trace(spid,txt) values(''+convert(nvarchar(32),@@spid)+'','''''' set @sql1=dbo.fn__inject(@txt) if abs(@dbg)>=@@nestlevel exec sp__printf ''%s%s'''')'',@sql,@sql1 exec(@sql+@sql1+'''''')'') end else begin set @sql=''insert into log_trace(ref_id,spid,txt) values(''+convert(nvarchar(32),@ref_id)+''-ident_current(''''log_trace''''),''+convert(nvarchar(32),@@spid)+'','''''' set @sql1=dbo.fn__inject(@txt) if abs(@dbg)>=@@nestlevel exec sp__printf ''%s%s'''')'',@sql,@sql1 exec(@sql+@sql1+'''''')'') if @@error<>0 begin exec(''alter table log_trace add ref_id int'') exec(@sql+@sql1+'''''')'') end end set @last_id=ident_current(''log_trace'') -- @@identity goto ret help: select @sql =''\nparameters:\n'' +''\t@init\t\t1 create log_trace\n'' +''\nsamples:\n'' +''\tsp__trace ''''test'''''' exec sp__usage ''sp__trace'',@sql ret: end -- [sp__log_trace]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__log_trace: -- ======================================================== sp__log_trace_search select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__log_trace_search',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130225 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__log_trace_search') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__log_trace_search') with nowait goto skip_sp__log_trace_search end if @ver>130225 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__log_trace_search') with nowait goto skip_sp__log_trace_search end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__log_trace_search') with nowait if exists( select top 1 null from sys.objects where name='sp__log_trace_search' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__log_trace_search] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130225\s.zaglio: adapted to new sp__udage v:110314\s.zaglio: renamed from deprecated sp__trace_search (see sp__log) v:090322\S.Zaglio: search into formatted log_trace */ CREATE proc [dbo].[sp__log_trace_search] @proc sysname=null, @days int=1, @id smallint=null, @like sysname=null as begin set nocount on declare @sql nvarchar(4000) if @proc is null and (@id is null) begin select @sql =''select top 100 percent dbo.fn__str_at(txt, ''''|'''', 2) as prc '' +''from dbo.log_trace l with (readpast) '' +''where substring(txt,24,1)=''''|'''' group by dbo.fn__str_at(txt, ''''|'''', 2)'' exec(@sql) exec sp__usage ''sp_log_trace'',@extra=''\n @proc can be % or a procedure\n @like is used in like %@like%'' goto ret end select top 100 percent id, ref_id + id-1 as rel_id, spid, convert(datetime,substring(txt,1,23)) date, dbo.fn__str_at(txt, ''|'', 2) as prc, replace(dbo.fn__str_at(txt, ''|'', 3),char(13)+char(10),'' '') as txt from dbo.log_trace l with (readpast) where substring(txt,24,1)=''|'' and (@days is null or convert(datetime,substring(txt,1,23))>getdate()-@days) and dbo.fn__str_at(txt, ''|'', 2) like ''%''+isnull(@proc,'''')+''%'' and (@id is null or [id]=@id) and (@like is null or txt like ''%''+@like+''%'') order by id desc ret: end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__log_trace_search: -- ================================================================ sp__log_view select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__log_view',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131014 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__log_view') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__log_view') with nowait goto skip_sp__log_view end if @ver>131014 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__log_view') with nowait goto skip_sp__log_view end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__log_view') with nowait if exists( select top 1 null from sys.objects where name='sp__log_view' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__log_view] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:131014\s.zaglio: d tag adjust v:121107\s.zaglio: a bug near @n of keep (now -@n) v:121105\s.zaglio: added KEEP option v:110513\s.zaglio: removed readpast v:110509\s.zaglio: removed out to #src because conflict !!!! v:110506\s.zaglio: adapted too new sp__log v:110505\s.zaglio: renamed into sp__log_view v:110504\s.zaglio: added md5 recordnize v:110422\s.zaglio: adapted to new log format v:100314\s.zaglio: search in log d:100314\s.zaglio: sp__log_show d:100314\s.zaglio: sp__log_search d:100314\s.zaglio: sp__trace_search t: exec sp__log ''1st test'',@key=''sp__log_search'' exec sp__log ''1st sub test'',@key=''sp__log_search'' t:sp__log_view 12 t:sp__log_view @what=null,@ref=2 t:sp__log_view #10 */ CREATE proc [dbo].[sp__log_view] @what sql_variant=null, @ref sql_variant=null, @opt sysname=null, @dbg int=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0,@dbg=isnull(@dbg,0), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @what is null and @ref is null goto help declare @key varbinary(256),@txt nvarchar(4000),@rid int, @bt varchar(32),@bk varchar(32),@id int,@top int, @keep bit,@n int,@dt datetime,@tdt nvarchar(4), @sql nvarchar(4000),@swhat nvarchar(4000),@sref nvarchar(128) select @bk=cast(sql_variant_property(@what,''BaseType'') as varchar), @bt=cast(sql_variant_property(@ref,''BaseType'') as varchar), @top=10000,@dt=getdate(),@swhat=cast(@what as nvarchar(4000)), @sref=cast(@ref as nvarchar(128)) if isnumeric(@sref)=1 select @rid=cast(@sref as int) else select top 1 @rid=id from [log] with (nolock) where [key]=@sref order by id desc if @swhat like ''%[dhwm]'' and isnumeric(left(@swhat,len(@swhat)-1))=1 begin if @rid is null goto err_ref select @n=left(@swhat,len(@swhat)-1),@tdt=right(@swhat,1)+right(@swhat,1) select @sql=''select @dt=dateadd(''+@tdt+'',-@n,@dt)'' exec sp_executesql @sql,N''@dt datetime out,@n int'',@dt=@dt out,@n=@n delete from [log] where rid=@rid and dt<@dt select @n=@@rowcount if @dbg>0 exec sp__printf ''-- delete %d records before %s'',@n,@dt goto ret end -- keep -- create table #src(lno int identity, line nvarchar(4000)) -- select * from #src drop table #src -- example: sp__log_view 0x3db54b02d3fa8a637c68bea25398155e,test if @bk in (''binary'',''varbinary'') begin if @ref is null goto err_ref -- select * from log where [key]=cast(''test'' as sql_variant) -- select * from log where [key]=cast(cast(''test'' as sql_variant) as nvarchar(256)) end if @bk in (''int'') select @id=cast(@what as int) if @bk in (''nvarchar'',''varchar'') begin select @txt=cast(@what as nvarchar(4000)) select @key=cast(@what as varbinary(256)) if left(@txt,1)=''#'' and isnumeric(substring(@txt,2,4000))=1 select @top=cast(substring(@txt,2,4000) as int), @txt=null, @key=null else select @top=1000 if charindex(''%'',@txt)>0 select @key=null end -- if @dbg=1 select @top,@id,@rid,@txt,@key select top (@top) -- select id, rid, dt, [key], convert(nvarchar(4000),c1) as txt, convert(money,c3) as n, convert(money,c4) as m, convert(int,c2) as [spid] from [log] with (nolock) where 1=1 and (@id is null or id=@id) and (@rid is null or rid=@rid) and (@key is null or [key]=@key) and (@txt is null or cast(c1 as nvarchar(4000)) like @txt) order by dt desc goto ret -- =================================================================== errors == err_ref: exec @ret=sp__err ''a reference not null and correct is required'' goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope show log info Parameters @what if numeric is the log id if hexadecimal is the key if contain % search lines like @what if begin with #nnn show the first nnn rows if end with D,H,W,M (days,hours,weeks,months) and @opt has "shrink", keep only lasts @what(DHWM) records @ref if present become the parent of the key group can be the parent id @opt options keep delete older logs if @what like %[dhwm] Examples -- show last 100 logs sp__log_view #100 -- show logs of this parent key sp__log_view 0x9c14ce8040deb2804c7c3bc111cc10dd,test -- show by id sp__log_view 12 sp__log_view "sys%" sp__log_view "15d","SP_MYPROC",@opt="keep" '' select distinct case when substring(cast([key] as nvarchar),1,1) like ''[a-zA-Z0-9]'' then convert(nvarchar(256),[key]) else dbo.fn__hex([key]) end as [key] into #keys from [log] exec sp__select_astext ''select * from #keys'' select @ret=-1 ret: return @ret end -- sp__log_view' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__log_view: -- ==================================================================== sp__loop select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__loop',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__loop') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__loop') with nowait goto skip_sp__loop end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__loop') with nowait goto skip_sp__loop end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__loop') with nowait if exists( select top 1 null from sys.objects where name='sp__loop' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__loop] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:091018\s.zaglio: loop into values, replacing in the template and execute or print it */ CREATE proc [dbo].[sp__loop] @tpl nvarchar(4000)=null, @x nvarchar(4000)=null, @y nvarchar(4000)=null, @z nvarchar(4000)=null, @parallel bit=1, @simul bit=0 as begin print ''todo: see inside'' /* exec sp__loop '' -- test inner temp tables create proc sp_temp_test as begin create table #test() select id,right(name,13) from tempdb..sysobjects where id=object_id(''''tempdb..#test'''') exec sp_temp_test -- drop table #test end g o drop proc sp_temp_test -- '' @x=''1,2,3'', @y=''id1 int|id1 real,p2c2 money,p2c3 text|id1 nvarchar(10),c2 int'', @z=''2,3,4'', @parallel=1, @simul=1 */ -- must return: /* create proc sp_temp_test2 as begin create table #test(id1 real,p2c2 money,p2c3 ntext) select id,right(name,13) from tempdb..sysobjects where id=object_id(''tempdb..#test'') exec sp_temp_test3 drop table #test end g o create proc sp_temp_test3 as begin create table #test(id1 nvarchar(10),c2 int) select id,right(name,13) from tempdb..sysobjects where id=object_id(''tempdb..#test'') drop table #test end g o drop proc sp_temp_test1 drop proc sp_temp_test2 drop proc sp_temp_test3 */ end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__loop: -- ========================================================= sp__maint_idxdefrag select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__maint_idxdefrag',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110923 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__maint_idxdefrag') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__maint_idxdefrag') with nowait goto skip_sp__maint_idxdefrag end if @ver>110923 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__maint_idxdefrag') with nowait goto skip_sp__maint_idxdefrag end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__maint_idxdefrag') with nowait if exists( select top 1 null from sys.objects where name='sp__maint_idxdefrag' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__maint_idxdefrag] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:index,maintenance,rebuild,fragmentation v:110923\s.zaglio: refined r:091018.1000\s.zaglio: defrag current db indexes t:sp__maint_idxdefrag run */ CREATE proc sp__maint_idxdefrag @opt sysname=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0,@opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- declare variables set nocount on declare @tablename varchar (128) declare @execstr varchar (255) declare @objectid int declare @indexid int declare @frag decimal declare @maxfrag decimal declare @run bit select @run=charindex(''|run|'',@opt) if @run=0 exec sp__printf ''-- use @opt=''''run'''' to execute it isntead of show'' -- decide on the maximum fragmentation to allow select @maxfrag = 8 -- declare cursor declare tables cursor for select ''[''+table_schema+''].[''+table_name+'']'' as table_name from information_schema.tables where table_type = ''base table'' and table_name not like ''t%'' -- create the table create table #fraglist ( objectname char (255), objectid int null, indexname char (255), indexid int null, lvl int null, countpages int null, countrows int null, minrecsize int null, maxrecsize int null, avgrecsize int null, forreccount int null, extents int null, extentswitches int null, avgfreebytes int null, avgpagedensity int null, scandensity decimal, bestcount int null, actualcount int null, logicalfrag decimal, extentfrag decimal null) -- open the cursor open tables -- loop through all the tables in the database fetch next from tables into @tablename while @@fetch_status = 0 begin -- do the showcontig of all indexes of the table exec sp__printf ''get info of %s'',@tablename insert into #fraglist exec (''dbcc showcontig ('''''' + @tablename + '''''') with fast, tableresults, all_indexes, no_infomsgs'') fetch next from tables into @tablename end -- close and deallocate the cursor close tables deallocate tables if @run=0 begin select case when logicalfrag >= @maxfrag then ''*'' else '''' end [!],objectname,indexname,logicalfrag,countrows from #fraglist where indexproperty (objectid, indexname, ''indexdepth'') > 0 order by [!] desc,logicalfrag desc select @ret=-1 end else begin -- declare cursor for list of indexes to be defragged declare indexes cursor for select objectname, objectid, indexid, logicalfrag from #fraglist where logicalfrag >= @maxfrag and indexproperty (objectid, indexname, ''indexdepth'') > 0 -- open the cursor open indexes -- loop through the indexes fetch next from indexes into @tablename, @objectid, @indexid, @frag while @@fetch_status = 0 begin print ''executing dbcc indexdefrag (0, '' + rtrim(@tablename) + '', '' + rtrim(@indexid) + '') - fragmentation currently '' + rtrim(convert(varchar(15),@frag)) + ''%'' select @execstr = ''dbcc indexdefrag (0, '' + rtrim(@objectid) + '', '' + rtrim(@indexid) + '')'' exec (@execstr) fetch next from indexes into @tablename, @objectid, @indexid, @frag end -- close and deallocate the cursor close indexes deallocate indexes end -- delete the temporary table drop table #fraglist return @ret end -- sp__maint_idxdefrag' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__maint_idxdefrag: -- ========================================================== sp__maint_idxstats select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__maint_idxstats',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=111116.1040 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__maint_idxstats') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__maint_idxstats') with nowait goto skip_sp__maint_idxstats end if @ver>111116.1040 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__maint_idxstats') with nowait goto skip_sp__maint_idxstats end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__maint_idxstats') with nowait if exists( select top 1 null from sys.objects where name='sp__maint_idxstats' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__maint_idxstats] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:index,optimization,statistic v:111116.1040\s.zaglio: use mssql perf. sp to list indexes to add */ CREATE proc sp__maint_idxstats @obj sysname = null as begin declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @obj is null goto help declare @db sysname,@sql nvarchar(max) select @db=db_name() if @obj=''#'' select @obj=null -- Find missing indices on your server select parsename(statement,3) db, parsename(statement,1) obj, equality_columns+isnull('',''+inequality_columns,''''), ''create index '' +upper(replace( ''idx_perf_'' + case when equality_columns is null then ltrim('''') else replace(rtrim(ltrim(replace(replace(replace(equality_columns,'','',''_''),''['',''''),'']'',''''))),char(32), ''_'') end + case when inequality_columns is null then ltrim('''') else replace(rtrim(ltrim(replace(replace(replace(inequality_columns,'','',''_''),''['',''''),'']'',''''))),char(32), ''_'') end + ''_''+cast(mid.index_handle as varchar) ,''__'',''_'')) + '' on '' + statement + '' ('' + case when equality_columns is null then '''' else replace(replace(equality_columns,''['',''''),'']'','''') end + case when inequality_columns is null then '')'' else '''' end + case when inequality_columns is null then '''' else + (case when equality_columns is null then '''' else '','' end) + inequality_columns + '')'' end + case when included_columns is null then '''' else + '' include('' + replace(replace(included_columns,''['',''''),'']'','''') + '')''end from sys.dm_db_missing_index_details mid inner join sys.dm_db_missing_index_groups mig on mig.index_handle = mid.index_handle inner join sys.dm_db_missing_index_group_stats migs on mig.index_group_handle = migs.group_handle where (@obj is null or @obj=parsename(statement,1)) order by parsename(statement,3),parsename(statement,1), avg_total_user_cost * avg_user_impact * (user_seeks + user_scans) desc; --- Find unused indices in your database select @sql = ''use '' + quotename(@db) select @sql = @sql + ''; select distinct object_name(sis.object_id) tablename, si.name as indexname, sc.name as columnname, sic.index_id, sis.user_seeks, sis.user_scans, sis.user_lookups, sis.user_updates from sys.dm_db_index_usage_stats sis inner join sys.indexes si on sis.object_id = si.object_id and sis.index_id = si.index_id and (si.is_disabled = 0 and si.is_primary_key=0) inner join sys.index_columns sic on sis.object_id = sic.object_id and sic.index_id = si.index_id inner join sys.columns sc on sis.object_id = sc.object_id and sic.column_id = sc.column_id where sis.database_id = db_id(@db) and (user_seeks = 0 and user_scans=0 and user_lookups=0) and si.type=2 and si.is_unique = 0 and si.is_primary_key = 0 and is_disabled = 0 and (@obj is null or @obj=object_name(sis.object_id)) order by tablename '' exec sp_executesql @sql,N''@db sysname, @obj sysname'',@db=@db,@obj=@obj goto ret help: exec sp__usage @proc,'' Scope use mssql perf. sp to list indexes to add Parameters @obj object to filter for indexes or # for all '' ret: return @ret end -- sp__maint_idxstats' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__maint_idxstats: -- ===================================================================== sp__man select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__man',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131013 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__man') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__man') with nowait goto skip_sp__man end if @ver>131013 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__man') with nowait goto skip_sp__man end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__man') with nowait if exists( select top 1 null from sys.objects where name='sp__man' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__man] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:131013\s.zaglio: show manual of object of search by keywords t:sp__man soap#call#web#service */ CREATE proc sp__man @what sysname = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @sep char -- =========================================================== initialization == if charindex(''#'',@what)>0 select @sep=''#'' else select @sep='','' -- ======================================================== second params chk == if nullif(@what,'''') is null goto help -- =============================================================== #tbls init == -- ===================================================================== body == ;with keywords(kword) as ( select case when right(token,1)=''s'' then left(token,len(token)-1) else token end as token from fn__str_split(@what,@sep) a ), subkeys(obj_id,obj,match) as ( select object_id as obj_id,name,1 from sys.objects cross apply fn__str_split(name,''_'') where token in (select kword from keywords) ), matches(obj,n) as ( select o.name, case when charindex(kws.kword,definition)>1 then 1 else 0 end match from sys.objects o join sys.sql_modules m on o.object_id=m.object_id cross apply keywords kws ) -- select * from matches order by obj desc,n desc -- select obj,n from matches union all select obj,1 from subkeys order by n desc , matched(obj,n) as ( select obj,sum(n) n from ( select obj,n from matches union all select obj,1 from subkeys ) md group by obj ) select top 5 * from matched order by n desc -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope show manual of object or search by keywords Notes actually not really uses k tag info but search into all definition Parameters [param] [desc] @what specific object or list of keywords separated by # or comma @opt (not used) @dbg (not used) Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__man' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__man: -- ===================================================================== sp__md5 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__md5',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110429 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__md5') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__md5') with nowait goto skip_sp__md5 end if @ver>110429 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__md5') with nowait goto skip_sp__md5 end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__md5') with nowait if exists( select top 1 null from sys.objects where name='sp__md5' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__md5] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110429\s.zaglio: specified for #src v:080808\S.Zaglio: calculate hash md5 of multiple strings */ CREATE proc sp__md5 @hash binary(16) =null out, @skip int=null as begin declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if object_id(''tempdb..#src'') is null goto help declare @buffer varbinary(64), @counter int,@line nvarchar(4000), @a bigint, @b bigint, @c bigint, @d bigint,@len int select @skip=isnull(@skip,0), @a = 0x67452301, @b = 0xefcdab89, @c = 0x98badcfe, @d = 0x10325476 declare cs cursor local for select isnull(line,'''') from #src order by lno open cs while 1=1 begin fetch next from cs into @line if @@fetch_status!=0 break if @skip>0 begin select @skip=@skip-1 continue end select @counter=1,@hash=0,@len=datalength(@line) -- exec sp__printf ''@l=%d, @h=%d, @line=%s'',@len,@hash,@line while @counter<=@len or @len=0 begin select @buffer=substring(cast( @line as varbinary(8000) ),@counter,55) select @counter=@counter+55 select @buffer = @buffer + 0x80 + cast( replicate( 0x00, 64 - 8 - 1 - datalength( @buffer ) ) as varbinary(64) ) + cast( (datalength( @buffer )*8 & 0xFF) as binary(1) ) + cast( (datalength( @buffer )*8 & 0xFF00)/256 as binary(1) ) + 0x0 select @a = dbo.fn__md5_r(0, @a, @b, @c, @d, cast( reverse( substring( @buffer, 00 + 1, 4 ) ) as binary(4) ), 128, 0xd76aa478 ) select @d = dbo.fn__md5_r(0, @d, @a, @b, @c, cast( reverse( substring( @buffer, 04 + 1, 4 ) ) as binary(4) ), 4096, 0xe8c7b756 ) select @c = dbo.fn__md5_r(0, @c, @d, @a, @b, cast( reverse( substring( @buffer, 08 + 1, 4 ) ) as binary(4) ), 131072, 0x242070db ) select @b = dbo.fn__md5_r(0, @b, @c, @d, @a, cast( reverse( substring( @buffer, 12 + 1, 4 ) ) as binary(4) ), 4194304,0xc1bdceee ) select @a = dbo.fn__md5_r(0, @a, @b, @c, @d, cast( reverse( substring( @buffer, 16 + 1, 4 ) ) as binary(4) ), 128, 0xf57c0faf ) select @d = dbo.fn__md5_r(0, @d, @a, @b, @c, cast( reverse( substring( @buffer, 20 + 1, 4 ) ) as binary(4) ), 4096, 0x4787c62a ) select @c = dbo.fn__md5_r(0, @c, @d, @a, @b, cast( reverse( substring( @buffer, 24 + 1, 4 ) ) as binary(4) ), 131072, 0xa8304613 ) select @b = dbo.fn__md5_r(0, @b, @c, @d, @a, cast( reverse( substring( @buffer, 28 + 1, 4 ) ) as binary(4) ), 4194304,0xfd469501 ) select @a = dbo.fn__md5_r(0, @a, @b, @c, @d, cast( reverse( substring( @buffer, 32 + 1, 4 ) ) as binary(4) ), 128, 0x698098d8 ) select @d = dbo.fn__md5_r(0, @d, @a, @b, @c, cast( reverse( substring( @buffer, 36 + 1, 4 ) ) as binary(4) ), 4096, 0x8b44f7af ) select @c = dbo.fn__md5_r(0, @c, @d, @a, @b, cast( reverse( substring( @buffer, 40 + 1, 4 ) ) as binary(4) ), 131072, 0xffff5bb1 ) select @b = dbo.fn__md5_r(0, @b, @c, @d, @a, cast( reverse( substring( @buffer, 44 + 1, 4 ) ) as binary(4) ), 4194304,0x895cd7be ) select @a = dbo.fn__md5_r(0, @a, @b, @c, @d, cast( reverse( substring( @buffer, 48 + 1, 4 ) ) as binary(4) ), 128, 0x6b901122 ) select @d = dbo.fn__md5_r(0, @d, @a, @b, @c, cast( reverse( substring( @buffer, 52 + 1, 4 ) ) as binary(4) ), 4096, 0xfd987193 ) select @c = dbo.fn__md5_r(0, @c, @d, @a, @b, cast( reverse( substring( @buffer, 56 + 1, 4 ) ) as binary(4) ), 131072, 0xa679438e ) select @b = dbo.fn__md5_r(0, @b, @c, @d, @a, cast( reverse( substring( @buffer, 60 + 1, 4 ) ) as binary(4) ), 4194304,0x49b40821 ) select @a = dbo.fn__md5_r(1, @a, @b, @c, @d, cast( reverse( substring( @buffer, 04 + 1, 4 ) ) as binary(4) ), 32, 0xf61e2562 ) select @d = dbo.fn__md5_r(1, @d, @a, @b, @c, cast( reverse( substring( @buffer, 24 + 1, 4 ) ) as binary(4) ), 512, 0xc040b340 ) select @c = dbo.fn__md5_r(1, @c, @d, @a, @b, cast( reverse( substring( @buffer, 44 + 1, 4 ) ) as binary(4) ), 16384, 0x265e5a51 ) select @b = dbo.fn__md5_r(1, @b, @c, @d, @a, cast( reverse( substring( @buffer, 00 + 1, 4 ) ) as binary(4) ), 1048576,0xe9b6c7aa ) select @a = dbo.fn__md5_r(1, @a, @b, @c, @d, cast( reverse( substring( @buffer, 20 + 1, 4 ) ) as binary(4) ), 32, 0xd62f105d ) select @d = dbo.fn__md5_r(1, @d, @a, @b, @c, cast( reverse( substring( @buffer, 40 + 1, 4 ) ) as binary(4) ), 512, 0x2441453 ) select @c = dbo.fn__md5_r(1, @c, @d, @a, @b, cast( reverse( substring( @buffer, 60 + 1, 4 ) ) as binary(4) ), 16384, 0xd8a1e681 ) select @b = dbo.fn__md5_r(1, @b, @c, @d, @a, cast( reverse( substring( @buffer, 16 + 1, 4 ) ) as binary(4) ), 1048576,0xe7d3fbc8 ) select @a = dbo.fn__md5_r(1, @a, @b, @c, @d, cast( reverse( substring( @buffer, 36 + 1, 4 ) ) as binary(4) ), 32, 0x21e1cde6 ) select @d = dbo.fn__md5_r(1, @d, @a, @b, @c, cast( reverse( substring( @buffer, 56 + 1, 4 ) ) as binary(4) ), 512, 0xc33707d6 ) select @c = dbo.fn__md5_r(1, @c, @d, @a, @b, cast( reverse( substring( @buffer, 12 + 1, 4 ) ) as binary(4) ), 16384, 0xf4d50d87 ) select @b = dbo.fn__md5_r(1, @b, @c, @d, @a, cast( reverse( substring( @buffer, 32 + 1, 4 ) ) as binary(4) ), 1048576,0x455a14ed ) select @a = dbo.fn__md5_r(1, @a, @b, @c, @d, cast( reverse( substring( @buffer, 52 + 1, 4 ) ) as binary(4) ), 32, 0xa9e3e905 ) select @d = dbo.fn__md5_r(1, @d, @a, @b, @c, cast( reverse( substring( @buffer, 08 + 1, 4 ) ) as binary(4) ), 512, 0xfcefa3f8 ) select @c = dbo.fn__md5_r(1, @c, @d, @a, @b, cast( reverse( substring( @buffer, 28 + 1, 4 ) ) as binary(4) ), 16384, 0x676f02d9 ) select @b = dbo.fn__md5_r(1, @b, @c, @d, @a, cast( reverse( substring( @buffer, 48 + 1, 4 ) ) as binary(4) ), 1048576,0x8d2a4c8a ) select @a = dbo.fn__md5_r(2, @a, @b, @c, @d, cast( reverse( substring( @buffer, 20 + 1, 4 ) ) as binary(4) ), 16, 0xfffa3942 ) select @d = dbo.fn__md5_r(2, @d, @a, @b, @c, cast( reverse( substring( @buffer, 32 + 1, 4 ) ) as binary(4) ), 2048, 0x8771f681 ) select @c = dbo.fn__md5_r(2, @c, @d, @a, @b, cast( reverse( substring( @buffer, 44 + 1, 4 ) ) as binary(4) ), 65536, 0x6d9d6122 ) select @b = dbo.fn__md5_r(2, @b, @c, @d, @a, cast( reverse( substring( @buffer, 56 + 1, 4 ) ) as binary(4) ), 8388608,0xfde5380c ) select @a = dbo.fn__md5_r(2, @a, @b, @c, @d, cast( reverse( substring( @buffer, 04 + 1, 4 ) ) as binary(4) ), 16, 0xa4beea44 ) select @d = dbo.fn__md5_r(2, @d, @a, @b, @c, cast( reverse( substring( @buffer, 16 + 1, 4 ) ) as binary(4) ), 2048, 0x4bdecfa9 ) select @c = dbo.fn__md5_r(2, @c, @d, @a, @b, cast( reverse( substring( @buffer, 28 + 1, 4 ) ) as binary(4) ), 65536, 0xf6bb4b60 ) select @b = dbo.fn__md5_r(2, @b, @c, @d, @a, cast( reverse( substring( @buffer, 40 + 1, 4 ) ) as binary(4) ), 8388608,0xbebfbc70 ) select @a = dbo.fn__md5_r(2, @a, @b, @c, @d, cast( reverse( substring( @buffer, 52 + 1, 4 ) ) as binary(4) ), 16, 0x289b7ec6 ) select @d = dbo.fn__md5_r(2, @d, @a, @b, @c, cast( reverse( substring( @buffer, 00 + 1, 4 ) ) as binary(4) ), 2048, 0xeaa127fa ) select @c = dbo.fn__md5_r(2, @c, @d, @a, @b, cast( reverse( substring( @buffer, 12 + 1, 4 ) ) as binary(4) ), 65536, 0xd4ef3085 ) select @b = dbo.fn__md5_r(2, @b, @c, @d, @a, cast( reverse( substring( @buffer, 24 + 1, 4 ) ) as binary(4) ), 8388608,0x04881d05 ) select @a = dbo.fn__md5_r(2, @a, @b, @c, @d, cast( reverse( substring( @buffer, 36 + 1, 4 ) ) as binary(4) ), 16, 0xd9d4d039 ) select @d = dbo.fn__md5_r(2, @d, @a, @b, @c, cast( reverse( substring( @buffer, 48 + 1, 4 ) ) as binary(4) ), 2048, 0xe6db99e5 ) select @c = dbo.fn__md5_r(2, @c, @d, @a, @b, cast( reverse( substring( @buffer, 60 + 1, 4 ) ) as binary(4) ), 65536, 0x1fa27cf8 ) select @b = dbo.fn__md5_r(2, @b, @c, @d, @a, cast( reverse( substring( @buffer, 08 + 1, 4 ) ) as binary(4) ), 8388608,0xc4ac5665 ) select @a = dbo.fn__md5_r(3, @a, @b, @c, @d, cast( reverse( substring( @buffer, 00 + 1, 4 ) ) as binary(4) ), 64, 0xf4292244 ) select @d = dbo.fn__md5_r(3, @d, @a, @b, @c, cast( reverse( substring( @buffer, 28 + 1, 4 ) ) as binary(4) ), 1024, 0x432aff97 ) select @c = dbo.fn__md5_r(3, @c, @d, @a, @b, cast( reverse( substring( @buffer, 56 + 1, 4 ) ) as binary(4) ), 32768, 0xab9423a7 ) select @b = dbo.fn__md5_r(3, @b, @c, @d, @a, cast( reverse( substring( @buffer, 20 + 1, 4 ) ) as binary(4) ), 2097152,0xfc93a039 ) select @a = dbo.fn__md5_r(3, @a, @b, @c, @d, cast( reverse( substring( @buffer, 48 + 1, 4 ) ) as binary(4) ), 64, 0x655b59c3 ) select @d = dbo.fn__md5_r(3, @d, @a, @b, @c, cast( reverse( substring( @buffer, 12 + 1, 4 ) ) as binary(4) ), 1024, 0x8f0ccc92 ) select @c = dbo.fn__md5_r(3, @c, @d, @a, @b, cast( reverse( substring( @buffer, 40 + 1, 4 ) ) as binary(4) ), 32768, 0xffeff47d ) select @b = dbo.fn__md5_r(3, @b, @c, @d, @a, cast( reverse( substring( @buffer, 04 + 1, 4 ) ) as binary(4) ), 2097152,0x85845dd1 ) select @a = dbo.fn__md5_r(3, @a, @b, @c, @d, cast( reverse( substring( @buffer, 32 + 1, 4 ) ) as binary(4) ), 64, 0x6fa87e4f ) select @d = dbo.fn__md5_r(3, @d, @a, @b, @c, cast( reverse( substring( @buffer, 60 + 1, 4 ) ) as binary(4) ), 1024, 0xfe2ce6e0 ) select @c = dbo.fn__md5_r(3, @c, @d, @a, @b, cast( reverse( substring( @buffer, 24 + 1, 4 ) ) as binary(4) ), 32768, 0xa3014314 ) select @b = dbo.fn__md5_r(3, @b, @c, @d, @a, cast( reverse( substring( @buffer, 52 + 1, 4 ) ) as binary(4) ), 2097152,0x4e0811a1 ) select @a = dbo.fn__md5_r(3, @a, @b, @c, @d, cast( reverse( substring( @buffer, 16 + 1, 4 ) ) as binary(4) ), 64, 0xf7537e82 ) select @d = dbo.fn__md5_r(3, @d, @a, @b, @c, cast( reverse( substring( @buffer, 44 + 1, 4 ) ) as binary(4) ), 1024, 0xbd3af235 ) select @c = dbo.fn__md5_r(3, @c, @d, @a, @b, cast( reverse( substring( @buffer, 08 + 1, 4 ) ) as binary(4) ), 32768, 0x2ad7d2bb ) select @b = dbo.fn__md5_r(3, @b, @c, @d, @a, cast( reverse( substring( @buffer, 36 + 1, 4 ) ) as binary(4) ), 2097152,0xeb86d391 ) -- exec sp__printf ''@c=%d, a=%d, b=%d, c=%d, d=%d'',@counter,@a,@b,@c,@d if @len=0 break end -- while counter end -- while 1=1 close cs deallocate cs select @hash = cast( reverse( cast( ( @a + 0x67452301 ) as binary(4) ) ) + reverse( cast( ( @b + 0xefcdab89 ) as binary(4) ) ) + reverse( cast( ( @c + 0x98badcfe ) as binary(4) ) ) + reverse( cast( ( @d + 0x10325476 ) as binary(4) ) ) as binary(16) ) goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope calculate hash for table #src (for single strings, use fn__md5) Parameters @skip skin @skip (header)lines before init to calculate Examples declare @hash binary(16) create table #src(lno int identity,line nvarchar(4000)) insert #src(line) select ''''Test line 1'''' insert #src(line) select ''''Test line 2'''' insert #src(line) select '''''''' insert #src(line) select null exec sp__md5 @hash out print @hash -- 0xC9AA7200A10304DD76F4C5B75F79C41C exec sp__md5 @hash out,1 print @hash -- 0x4F67A2ECFC0E84DB22585F13AAC9F8E6 exec sp__md5 @hash out,2 print @hash -- 0xD4588FC69881818B29010299103452BF exec sp__md5 @hash out,3 print @hash -- 0xD41D8CD98F00B204E9800998ECF8427E drop table #src '' ret: return @ret end -- sp__md5' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__md5: -- =================================================================== sp__merge select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__merge',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130710 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__merge') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__merge') with nowait goto skip_sp__merge end if @ver>130710 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__merge') with nowait goto skip_sp__merge end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__merge') with nowait if exists( select top 1 null from sys.objects where name='sp__merge' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__merge] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130710\s.zaglio: added lkey for logic keys v:130211\s.zaglio: bug that causes a lost of last added fld(see code) v:120413\s.zaglio: add. exclusion of identity fld v:120113\s.zaglio: added code for correct compare v:110407\s.zaglio: added @no_ins,no_upd and code option v:110406\s.zaglio: added @excludes v:110322\s.zaglio: better help; added @where v:100928\s.zaglio: append mode, when @keys = @flds_tbl v:100730.1100\s.zaglio: more help v:100724\s.zaglio: added cmp option r:100718\s.zaglio: insert/update into one solution t:drop proc sp__merge t:sp__merge ''test_form'',''id'' */ CREATE proc sp__merge @tbl sysname =null, @flds_tbl nvarchar(4000) =null, -- or from @from sysname =null, -- or keys @flds_from nvarchar(4000) =null, @keys nvarchar(4000) =null, @flds_cmp nvarchar(4000) =null, -- upd fields @where nvarchar(4000) =null, @no_ins nvarchar(4000) =null, @no_upd nvarchar(4000) =null, @error int = null out, @inserted bigint = null out, @updated bigint = null out, @opt sysname =null, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @ret=0 select @opt=dbo.fn__str_quote(@opt,''|'') -- declarations declare @flds nvarchar(4000),@drop bit,@code bit declare @excludes table(ins bit,obj sysname) declare @op_cmp bit,@op_nochk bit,@op_moc bit, @op_121 bit,@op_nofmt bit,@op_lkey bit select @op_cmp=charindex(''|cmp|'',@opt), @op_nochk=charindex(''|nochk|'',@opt), @op_moc=charindex(''|moc|'',@opt), @op_121=charindex(''|121|'',@opt), @op_nofmt=charindex(''|nofmt|'',@opt), @op_lkey=charindex(''|lkey|'',@opt) -- simple: to,from,[key] if not @tbl is null and not @flds_tbl is null and not @from is null and @flds_from is null and @keys is null begin if @dbg>1 exec sp__printf ''simple syntax'' select @keys=@from,@from=@flds_tbl,@flds_tbl=null end if @tbl is null and @from is null goto help if @op_nochk=0 and (dbo.fn__exists(@tbl,null)=0 or dbo.fn__exists(@from,null)=0) goto err_notf -- drop table #fld create table #fld( tid tinyint, -- 1=fld,2=key,3=upd id int identity, tbl sysname null, fld sysname, [from] sysname null, from_fld sysname null, sep nvarchar(4) null, cmm sysname null, t_f as rtrim(tbl)+rtrim(fld), f_f as rtrim([from])+rtrim(from_fld), cmp_flds as ''or (''+rtrim(tbl)+rtrim(fld)+''!=''+ rtrim([from])+rtrim(from_fld)+ '' or ((''+rtrim(tbl)+rtrim(fld)+'' is null or ''+ rtrim([from])+rtrim(from_fld)+'' is null) ''+ ''and not coalesce(''+rtrim(tbl)+rtrim(fld)+'',''+ rtrim([from])+rtrim(from_fld)+ '') is null))'' ) declare @src table (lno int identity primary key,line nvarchar(4000)) declare @n int,@m int,@cr nchar(1),@lf nchar(1),@tab nchar(1), @sql nvarchar(4000),@id int select @tbl=dbo.fn__sql_unquotename(@tbl), @from=dbo.fn__sql_unquotename(@from), @cr=cr,@lf=lf,@tab=tab, @no_ins=replace(@no_ins,''|'','',''), @no_upd=replace(@no_upd,''|'','',''), @code=0 from dbo.fn__sym() insert @excludes(ins,obj) select 1,token from dbo.fn__str_table(@no_ins,'','') insert @excludes(ins,obj) select 0,token from dbo.fn__str_table(@no_upd,'','') /* exec sp__merge ''tbl'', ''c1, c2, c3, c4,c5'', ''from'', ''c1,c2, c3,c4'', ''c1,c2, c3 ,c4'',@dbg=1 */ -- adjust programming format select @n=4 while @n>0 begin if @dbg>1 exec sp__printf ''adjusting flds of param %d'',@n if @n=4 select @flds=@flds_tbl if @n=3 select @flds=@flds_from if @n=2 select @flds=@keys if @n=1 select @flds=@flds_cmp select @flds=replace(@flds,@tab,'' '') select @flds=replace(@flds,@cr,'''') select @flds=replace(@flds,@lf,'''') while charindex('' '',@flds)>0 select @flds=replace(@flds,'' '','' '') while charindex('', '',@flds)>0 select @flds=replace(@flds,'', '','','') while charindex('' ,'',@flds)>0 select @flds=replace(@flds,'' ,'','','') if @n=4 select @flds_tbl=@flds if @n=3 select @flds_from=@flds if @n=2 select @keys=@flds if @n=1 select @flds_cmp=@flds select @n=@n-1 end -- while /* ================================ body ================================== */ if @keys is null or @dbg>1 begin exec sp__printf ''--tbl=%s\n--fld=%s\n--from=%s\n--ffld=%s\n--key=%s'', @tbl,@flds_tbl,@from,@flds_from,@keys if @keys is null select @code=1, @keys=@flds_tbl, @from=@tbl, @flds_tbl=null end -- code mode if @keys=''*'' select @keys=dbo.fn__flds_of(@tbl,'','',null) if @flds_tbl is null select @flds_tbl=dbo.fn__flds_of(@tbl,'','',''%id%'') if @flds_from is null select @flds_from =dbo.fn__flds_of(@from,'','',''%id%'') select @n=dbo.fn__str_count(@flds_tbl,'',''), @m=dbo.fn__str_count(@flds_from,'','') if @n!=@m and @op_moc=0 goto err_nmsf declare @fsrc tinyint,@fdst tinyint,@fkey tinyint,@fcmp tinyint select @fsrc=1,@fkey=2,@fcmp=3 -- to fields insert into #fld(tid,fld) select @fsrc,token from dbo.fn__str_table(@flds_tbl,'','') where not token in (select obj from @excludes) -- from fields one to one if @op_121=1 update fld set from_fld=ff.token from #fld fld join dbo.fn__str_table(@flds_from,'','') ff on ff.pos=fld.id and @fsrc=fld.tid else begin select @n=count(*) from #fld update fld set from_fld=ff.token from #fld fld join dbo.fn__str_table(@flds_from,'','') ff on ff.token=fld.fld and @fsrc=fld.tid if @@rowcount!=@n and @op_moc=0 goto err_nmsf end -- remove not matched fields delete from #fld where from_fld is null update #fld set sep=case when id=(select max(id) from #fld) then '''' else '','' end where 1=#fld.tid -- keys select @n=dbo.fn__str_count(@keys,'','') insert into #fld(tid,fld,from_fld,sep) select @fkey,dbo.fn__str_at(token,''='',1),isnull(dbo.fn__str_at(token,''='',2),token), case when pos=1 then ''on '' else ''and '' end from dbo.fn__str_table(@keys,'','') join #fld fld on dbo.fn__str_at(token,''='',1)=fld.fld and @fsrc=fld.tid order by pos if @@rowcount!=@n goto err_nmkf if @dbg>1 exec sp__select_astext '' select case tid when 1 then ''''S'''' when 2 then ''''K'''' when 3 then ''''C'''' when 4 then ''''D'''' end as [T],* from #fld where tid=2 order by id '' -- extra update fields to compare select @n=dbo.fn__str_count(@flds_cmp,'','') insert into #fld(tid,fld,from_fld) select @fcmp,fld.fld,from_fld from #fld fld join dbo.fn__str_table(@flds_cmp,'','') on fld.fld=token and @fsrc=fld.tid if @@rowcount!=@n goto err_nmuf -- add table info and format fields update #fld set tbl=''tbl.'', fld=quotename(fld), [from]= case when left(from_fld,1) like ''[0-9"(]'' then '''' else ''tmp.'' end, from_fld= case when left(from_fld,1) like ''[0-9"(]'' then from_fld else quotename(from_fld) end -- format if @op_nofmt=0 begin select @n=max(len(tbl+fld)),@m=max(len([from]+from_fld)) from #fld update #fld set fld=left(fld+replicate('' '',@n-len(tbl)),@n-len(tbl)), from_fld=left(from_fld+replicate('' '',@m-len([from])),@m-len([from])), cmm=dbo.fn__comment(quotename(@tbl)+''.''+quotename(fld)) end if @dbg>1 exec sp__select_astext '' select case tid when 1 then ''''S'''' when 2 then ''''K'''' when 3 then ''''C'''' when 4 then ''''D'''' end as [T],* from #fld order by id '' if @op_cmp=1 begin insert @src select ''select'' insert @src select top 1 '' case when ''+t_f+'' is null '' from #fld where tid=@fsrc order by id insert @src select '' then ''''+'''' '' if @flds_cmp is null insert @src select '' else '''''''''' else begin insert @src select '' else case when 1!=1'' insert @src select '' ''+cmp_flds from #fld where tid=@fcmp order by id insert @src select '' then ''''<'''' else '''''''''' insert @src select '' end'' end -- flds_cmp insert @src select '' end as [*],'' insert @src select '' ''+t_f+'',''+f_f+'' [<<]''+sep from #fld where tid=@fsrc order by id insert @src select ''from ''+quotename(@from)+'' tmp '' insert @src select ''left join ''+quotename(@tbl)+'' tbl '' insert @src select '' ''+sep+''(''+t_f+''=''+f_f+ case when @op_lkey=1 then '' or (''+t_f+'' is null and ''+f_f+'' is null)'' else '''' end+'')'' from #fld where tid=2 insert @src select ''where 1=1'' if not @where is null insert @src select ''and ''+@where end -- cmp else begin -- ins/upd -- generate update and insert script insert @src select ''declare @n bigint, @error int'' -- title if not dbo.fn__comment(@tbl) is null insert @src select ''-- ''+@tbl+'': ''+dbo.fn__comment(@tbl) -- append/update if 0=( select count(*) from #fld f left join #fld k on k.tid=@fkey and k.fld=f.fld where f.tid=@fsrc and k.id is null) begin if @dbg>1 exec sp__printf ''-- append mode'' end else begin insert @src select '''' insert @src select ''update tbl set'' insert @src select '' ''+f.tbl+f.fld+''=''+ f.f_f+f.sep+ isnull('' -- ''+f.cmm,'''') from #fld f left join #fld k on k.tid=@fkey and k.fld=f.fld where f.tid=@fsrc -- and k.id is null 130211\s.zaglio order by f.id insert @src select ''from ''+quotename(@tbl)+'' tbl '' insert @src select ''join ''+quotename(@from)+'' tmp '' insert @src select '' ''+sep+''(''+t_f+''=''+f_f+ case when @op_lkey=1 then '' or (''+t_f+'' is null and ''+f_f+'' is null)'' else '''' end+'')'' from #fld where tid=2 if not @flds_cmp is null begin insert @src select ''where ''+ isnull(''(''+@where+'') and '','''')+ ''(1!=1'' select top 1 @id=id from #fld where tid=3 order by id insert @src select '' ''+cmp_flds from #fld where tid=@fcmp order by id insert @src select '' )'' end insert @src select '''' insert @src select ''select @error=@@error,@n=@@rowcount'' if @code=0 insert @src select ''update #returns set error=@error,updated=@n'' insert @src select ''if @error!=0 goto end_ins_upd'' insert @src select '''' end -- update -- insert insert @src select ''insert into ''+quotename(@tbl)+''('' insert @src select '' ''+fld+sep from #fld where tid=@fsrc order by id insert @src select '' )'' insert @src select ''select'' insert @src select '' ''+f_f+sep from #fld where tid=@fsrc order by id insert @src select ''from ''+quotename(@from)+'' tmp '' insert @src select ''left join ''+quotename(@tbl)+'' tbl '' insert @src select '' ''+sep+''(''+t_f+''=''+f_f+ case when @op_lkey=1 then '' or (''+t_f+'' is null and ''+f_f+'' is null)'' else '''' end+'')'' from #fld where tid=@fkey insert @src select ''where 1=1'' if @op_lkey=0 insert @src select top 1 -- only one key fld is necessary '' and ''+t_f+'' is null'' from #fld where tid=@fkey order by id else -- when the "primary key" is "logic" ... insert @src select -- ... all fields are necessary '' and ''+t_f+'' is null'' from #fld where tid=@fkey order by id insert @src select '''' insert @src select ''select @error=@@error,@n=@@rowcount'' if @code=0 insert @src select ''update #returns set error=@error,inserted=@n'' insert @src select ''end_ins_upd:'' insert @src select ''-- if @error!=0 rollback'' end -- !cmp if @code=0 create table #src(lno int identity, line nvarchar(4000)) if @dbg>0 begin select @n=max(lno) from #src select @n=isnull(@n,0) insert #src(line) select line from @src order by lno exec sp__print_table ''#src'' delete from #src where lno>@n if @op_cmp=0 exec sp__printframe ''### above code is not executed ###'' end if @code=0 and (@dbg=0 or @op_cmp!=0) begin create table #returns(error int,updated bigint,inserted bigint) insert #returns select 0,0,0 insert #src(line) select line from @src order by lno exec @ret=sp__script_compile if @ret!=0 exec sp__print_table ''#src'' select @error=error,@inserted=inserted,@updated=updated from #returns drop table #returns end if @code=1 begin if object_id(''tempdb..#src'') is null select line from @src order by lno else insert #src(line) select line from @src order by lno end drop table #fld if @code=0 drop table #src goto ret /* ================================ errors ================================ */ err_nmuf: exec @ret=sp__err ''compare fields for update do not match with fields of tables'',@proc goto ret err_nmkf: exec @ret=sp__err ''key fields do not match with fields of tables'',@proc goto ret err_nmsf: exec @ret=sp__err ''selected fields do not match in both tables (see options 121,moc)'',@proc goto ret err_notf: exec @ret=sp__err ''source or dest table not found (see options nochk)'',@proc goto ret err_whre: exec @ret=sp__err ''@where param is not compatible with ...'',@proc goto ret /* ================================ help ================================== */ help: exec sp__usage @proc,'' Scope generate and run code for update and insert of records Parameters Code generation syntax @tbl as @tbl @flds_tbl as @keys (NB: show generated code to cut and paste into I/O proc this is the better practice do not use directly sp__merge for I/O because there are many differences between two systems except for sync between two well normalized dbs) Simple syntax: @tbl as @tbl @flds_tbl as @from @from as @keys Complete syntax: @tbl to/destination table @flds_tbl destination fields @from from/source table @flds_from source fields @keys fields of keys for join (* for all of @tbl) @flds_cmp fields for unic key for effective changes for update @where condition applied to @tbl (uses tbl alias) @no_ins exclude this fields (separated by comma) from insert list see code option @no_upd exclude this fields (separated by comma) from update list see code option @error return value of @error happened after insert or update @inserted return number of rows inserted @updated return number of rows update @opt see below @dbg if 1 show the generated code without execute it ### this is useful to use sp__merge as code generatore ### if 2 show debug info about inside tables Options 121 match 1st field of 1st table with 1st field of 2nd table and so on moc match only common fields, that exist in both tables nochk do not check existance of tables nofmt dot not format lkey set keys as logic and add compare of nulls cmp show result of a compare select tbl.c1,tmp.c1 [<-] dbg (todo) esecute ins/upd row by row with a cursor Notes The append mode happen when the key is all fields. So only the insert statement is executed. Examples -- operative table create table tst_base(id int, k1 sysname null, c datetime,act sysname) insert tst_base select row id,dbo.fn__format(row,"[eng]",default) k1,getdate(),"base" from fn__range(1,5,1) -- the last two line is unchanged -- temporary working table select id,k1,c,"delta" as act into #delta from tst_base delete from tst_base where id=1 -- this will added update #delta set c=c+1 where id=2 -- this will updated update tst_base set c=null where id=3 -- this test update of nulls update tst_base set c=null where id=4 -- this test not update of nulls update #delta set c=null where id=4 -- this test not update of nulls -- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< direction -- test results using only keys exec sp__merge "tst_base","#delta","id,k1",@opt="cmp",@dbg=1 -- test results using keys and other fields exec sp__merge "tst_base","#delta","id,k1",@flds_cmp="c",@opt="cmp",@dbg=1 -- test code with extra flds comp exec sp__merge @tbl="tst_base", @from="#delta", @keys="id,k1", @flds_cmp="c,act" ,@dbg=1 -- append test mode exec sp__merge "tst_base","#delta","*",@opt="cmp",@dbg=1 -- code generation test exec sp__merge "tst_base","id,k1",@flds_cmp="c" -- run it effectivelly (no dbg, no cmp) with where exec sp__merge @tbl="tst_base", @from="#delta", @keys="id,k1", @flds_cmp="c", @where="tbl.id!=2" -- only 1st line is added and 3rd modified select * from tst_base drop table #delta drop table tst_base '' select @ret=-1 /* ================================ exit ================================== */ ret: return @ret end -- proc sp__merge' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__merge: -- =================================================================== sp__nulls select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__nulls',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110213 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__nulls') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__nulls') with nowait goto skip_sp__nulls end if @ver>110213 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__nulls') with nowait goto skip_sp__nulls end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__nulls') with nowait if exists( select top 1 null from sys.objects where name='sp__nulls' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__nulls] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110213\s.zaglio: nullize the parameters t: declare @v sysname,@i int,@r real,@d datetime select @v='''',@i=0,@d=0,@r=0.0 exec sp__nulls @v out,@i out,@d out,@r out print isnull(@v,''(null)'') print isnull(@i,0) print isnull(@r,0) print isnull(@d,0) */ create proc sp__nulls @v0 nvarchar(4000) = null out, @v1 nvarchar(4000) = null out, @v2 nvarchar(4000) = null out, @v3 nvarchar(4000) = null out, @v4 nvarchar(4000) = null out, @v5 nvarchar(4000) = null out, @v6 nvarchar(4000) = null out, @v7 nvarchar(4000) = null out, @v8 nvarchar(4000) = null out, @v9 nvarchar(4000) = null out, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- ========================================================= param formal chk == exec @ret=sp__chknulls @v0,@v1,@v2,@v3,@v4,@v5,@v6,@v7,@v8,@v9 if @ret=1 goto help -- ============================================================== declaration == declare @d0 sysname -- =========================================================== initialization == -- ======================================================== second params chk == -- ===================================================================== body == select @d0=convert(sysname,convert(datetime,0)) if isdate(@v0)=1 select @v0=convert(sysname,convert(datetime,@v0)) if @v0 in ('''',''0'',@d0) select @v0=null if isdate(@v1)=1 select @v1=convert(sysname,convert(datetime,@v1)) if @v1 in ('''',''0'',@d0) select @v1=null if isdate(@v2)=1 select @v2=convert(sysname,convert(datetime,@v2)) if @v2 in ('''',''0'',@d0) select @v2=null if isdate(@v3)=1 select @v3=convert(sysname,convert(datetime,@v3)) if @v3 in ('''',''0'',@d0) select @v3=null if isdate(@v4)=1 select @v4=convert(sysname,convert(datetime,@v4)) if @v4 in ('''',''0'',@d0) select @v4=null if isdate(@v5)=1 select @v5=convert(sysname,convert(datetime,@v5)) if @v5 in ('''',''0'',@d0) select @v5=null if isdate(@v6)=1 select @v6=convert(sysname,convert(datetime,@v6)) if @v6 in ('''',''0'',@d0) select @v6=null if isdate(@v7)=1 select @v7=convert(sysname,convert(datetime,@v7)) if @v7 in ('''',''0'',@d0) select @v7=null if isdate(@v8)=1 select @v8=convert(sysname,convert(datetime,@v8)) if @v8 in ('''',''0'',@d0) select @v8=null if isdate(@v9)=1 select @v9=convert(sysname,convert(datetime,@v9)) if @v9 in ('''',''0'',@d0) select @v9=null goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope nullize the parameters if: "" in strings,0 in numbers and dates Examples declare @v sysname,@i int,@r real,@d datetime select @v='''',@i=0,@d=0,@r=0.0 exec sp__nulls @v out,@i out,@d out,@r out print isnull(@v,''''(null)'''') print isnull(@i,0) print isnull(@r,0) print isnull(@d,0) '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__nulls' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__nulls: -- ============================================================== sp__os_whereis select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__os_whereis',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140107.1700 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__os_whereis') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__os_whereis') with nowait goto skip_sp__os_whereis end if @ver>140107.1700 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__os_whereis') with nowait goto skip_sp__os_whereis end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__os_whereis') with nowait if exists( select top 1 null from sys.objects where name='sp__os_whereis' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__os_whereis] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:search,program,command,file,path,x86,any,system,64bit v:140107.1700\s.zaglio: search path of a program or command t:sp__os_whereis ''ftp.exe'',@dbg=1 t:sp__os_whereis ''winscp\winscp.com'',@dbg=1 t:sp__os_whereis ''winscp\nonscp.com'',@dbg=1 t:sp__os_whereis ''windows nt\accessories\wordpad.exe'',@dbg=1 t:xp_cmdshell ''C:\"Program Files"\"winscp"\"winscp.com"'' */ CREATE proc sp__os_whereis @prg nvarchar(1024) = null out, @opt sysname = null, @dbg int = null as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- is the verbosity level -- ============================================================== declaration == declare @path nvarchar(1024),@env nvarchar(1024),@i int, @tmp nvarchar(1024),@cmd nvarchar(1024),@envs nvarchar(4000) -- =========================================================== initialization == if @prg is null goto help -- ======================================================== second params chk == if left(@prg,1)=''\'' raiserror(''path of program must be relative'',16,1) -- =============================================================== #tbls init == -- ===================================================================== body == -- xp_cmdshell ''set'' -- xp_cmdshell ''dir %SystemRoot%\system32\ftp.exe'' -- xp_cmdshell ''dir %SystemRoot%\wow*'' select @envs=''SystemRoot|ProgramFiles(x86)|ProgramFiles'' declare cs cursor local for select pos,token from dbo.fn__str_split(@envs,''|'') open cs while 1=1 begin fetch next from cs into @i,@env if @@fetch_status!=0 break -- init env and path select @path=case @i when 1 then ''System32\'' else '''' end select @tmp=null exec sp__get_env @tmp out,@env if @tmp is null continue if right(@tmp,1)!=''\'' select @tmp=@tmp+''\'' select @path=@tmp+@path+@prg select @cmd=''dir "''+@path+''"'' exec @ret=xp_cmdshell @cmd,no_output if @ret=0 begin -- convert path for dir into path for execute select @path=replace(replace(@path,''\'',''"\"''),'':"\"'','':\"'')+''"'' break end end -- cursor cs close cs deallocate cs select @prg=case @ret when 0 then @path else null end if @dbg=1 exec sp__printf ''@prg:%s'',@prg -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope search into system and program paths the program and return the full path Parameters [param] [desc] @prg (out) the name of command or of program to search out the full path NB: do not look into subdirectory, so the relative path of the program must be specified (ex. winscp\winscp.com) @opt not used @dbg debug level 1 basic info and do not execute dynamic sql 2 more details (usually internal tables) and execute dsql 3 basic info, execute dsql and show remote info Examples @declare @prg nvarchar(4000) select @prg="ftp" exec sp__os_whereis @prg out if @prg is null raiserror(...) '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__os_whereis' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__os_whereis: -- ============================================================ sp__outputbuffer select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__outputbuffer',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080923 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__outputbuffer') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__outputbuffer') with nowait goto skip_sp__outputbuffer end if @ver>080923 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__outputbuffer') with nowait goto skip_sp__outputbuffer end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__outputbuffer') with nowait if exists( select top 1 null from sys.objects where name='sp__outputbuffer' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__outputbuffer] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080923\S.Zaglio: used to get complete error description of @@error t:begin declare @s nvarchar(2000) exec(''truncate table_test'') exec sp__outputbuffer @s out print @s end */ CREATE PROC sp__outputbuffer @errMessage nvarchar(1000) out AS set nocount on BEGIN DECLARE @dbccrow nchar(77) ,@sql nvarchar(2000) ,@hex nchar(2) ,@byte int ,@pos int ,@numMsg int ,@gather int ,@count int ,@byteNum int ,@msgLen int ,@errMsgLen int ,@nchar int ,@errNumber bigint ,@errState int ,@errLevel int ,@errInstance nvarchar(256) ,@errProcedure nvarchar(256) ,@errLine int /* A buffer sample 00000000 04 01 00 c8 00 37 01 00 aa 30 00 50 c3 00 00 01 ...È.7..ª0.PÃ... 00000010 10 07 00 54 00 45 00 53 00 54 00 20 00 30 00 31 ...T.E.S.T. .0.1 00000020 00 0a 45 00 4e 00 54 00 45 00 52 00 50 00 52 00 ..E.N.T.E.R.P.R. 00000030 49 00 53 00 45 00 00 01 00 00 00 fd 03 00 f6 00 I.S.E......ý..ö. 00000040 00 00 00 00 00 00 00 00 aa 30 00 50 c3 00 00 02 ........ª0.PÃ... 00000050 11 07 00 54 00 45 00 53 00 54 00 20 00 30 00 32 ...T.E.S.T. .0.2 00000060 00 0a 45 00 4e 00 54 00 45 00 52 00 50 00 52 00 ..E.N.T.E.R.P.R. 00000070 49 00 53 00 45 00 00 02 00 00 00 fd 03 00 f6 00 I.S.E......ý..ö. 00000080 00 00 00 00 00 00 00 00 aa 30 00 50 c3 00 00 03 ........ª0.PÃ... 00000090 12 07 00 54 00 45 00 53 00 54 00 20 00 30 00 33 ...T.E.S.T. .0.3 000000a0 00 0a 45 00 4e 00 54 00 45 00 52 00 50 00 52 00 ..E.N.T.E.R.P.R. 000000b0 49 00 53 00 45 00 00 03 00 00 00 fd 02 00 f6 00 I.S.E......ý..ö. 000000c0 00 00 00 00 00 00 00 00 30 00 20 00 36 00 64 00 ........0. .6.d. We need to scan the buffer for the byte marker 0xAA that starts an error message. The problem with this approach is that if the buffer contains any user data it might have the marker byte and thus provoking a false response. */ -- Catch the output buffer. CREATE TABLE #DBCCOUT (col1 nchar(77)) INSERT INTO #DBCCOUT EXEC (''DBCC OUTPUTBUFFER(@@spid)'') CREATE TABLE #errors ( errNumber bigint ,errState int ,errLevel int ,errMessage nvarchar(1000) ,errInstance nvarchar(256) ,errProcedure nvarchar(256) ,errLine int ) -- Step through the buffer lines. DECLARE error_cursor CURSOR STATIC FORWARD_ONLY FOR SELECT col1 FROM #DBCCOUT ORDER BY col1 -- Init variable, and open cursor. OPEN error_cursor FETCH NEXT FROM error_cursor INTO @dbccrow -- Count the number of error messages SET @numMsg = 0 SET @pos = 12 SET @gather = 0 -- Now assemble rest of string. WHILE (@@FETCH_STATUS = 0) BEGIN Start: IF (@pos > 57) BEGIN SET @pos = 12 GOTO NextRow END -- Get a byte from th stream SET @hex = Substring(@dbccrow, @pos, 2) -- Convert hexstring to int SELECT @sql = ''SELECT @int = convert(int, 0x00'' + @hex + '')'' EXEC sp_executesql @sql, N''@int int OUTPUT'', @byte output -- move to the next byte SET @pos = @pos + 3 IF (@gather = 0) BEGIN /* * Searching for the 0xAA marker */ IF (@byte != 170) GOTO Start SET @gather = 1 SET @count = 0 SET @msgLen = 0 GOTO Start END IF (@gather = 1) BEGIN /* * Get the Message Length */ SET @count = @count + 1 SET @msgLen = (@msgLen * 256) + @byte IF (@count = 2) BEGIN SET @count = 0 SET @byteNum = 0 SET @errNumber = 0 SET @gather = 2 END GOTO Start END /* * Count the number of bytes of the message */ IF (@gather > 1) SET @byteNum = @byteNum + 1 IF (@gather = 2) BEGIN /* * Get the error message */ SET @errNumber = IsNull(@errNumber, 0) + (@byte * power(256, @count)) SET @count = @count + 1 IF (@count = 4) BEGIN SET @count = 0 SET @gather = 3 END GOTO Start END IF (@gather = 3) BEGIN /* * Get the Error State */ SET @gather = 4 SET @errState = @byte GOTO Start END IF (@gather = 4) BEGIN /* * Get the Error Level */ SET @gather = 5 SET @errLevel = @byte GOTO Start END IF (@gather = 5) BEGIN /* * Get the error message length */ SET @errMsgLen = IsNull(@errMsgLen, 0) + (@byte * Power(256, @count)) SET @count = @count + 1 IF (@count = 2) BEGIN SET @nchar = 0 SET @count = 0 SET @gather = 6 END GOTO Start END IF (@gather = 6) BEGIN IF (@errMsgLen > 0) BEGIN /* * Get the error message text */ SET @nchar = IsNull(@nchar, 0) + (@byte * Power(256, @count)) SET @count = @count + 1 IF (@count = 2) BEGIN SET @count = 0 SET @errMessage = IsNull(@errMessage, '''') + nchar(@nchar) SET @nchar = 0 END IF (Len(@errMessage) = @errMsgLen) SET @gather = 7 GOTO Start END ELSE SET @gather = 7 END IF (@gather = 7) BEGIN /* * Get the instance size */ SELECT @gather = 8 ,@errMsgLen = @byte ,@nchar = 0 Goto Start END IF (@gather = 8) BEGIN IF (@errMsgLen > 0) BEGIN /* * Get the instance name */ SET @nchar = IsNull(@nchar, 0) + (@byte * Power(256, @count)) SET @count = @count + 1 IF (@count = 2) BEGIN SET @count = 0 SET @errInstance = IsNull(@errInstance, '''') + nchar(@nchar) SET @nchar = 0 END IF (Len(@errInstance) = @errMsgLen) SET @gather = 9 GOTO Start END ELSE SET @gather = 9 END IF (@gather = 9) BEGIN /* * Get the procedure size */ SELECT @gather = 10 ,@errMsgLen = @byte ,@nchar = 0 Goto Start END IF (@gather = 10) BEGIN IF (@errMsgLen > 0) BEGIN /* * Get the procedure name */ SET @nchar = IsNull(@nchar, 0) + (@byte * Power(256, @count)) SET @count = @count + 1 IF (@count = 2) BEGIN SET @count = 0 SET @errProcedure = IsNull(@errProcedure, '''') + nchar(@nchar) SET @nchar = 0 END IF (Len(@errProcedure) = @errMsgLen) SET @gather = 11 GOTO Start END ELSE SET @gather = 11 END IF (@gather = 11) BEGIN /* * Get the error message length */ SET @errLine = IsNull(@errLine, 0) + (@byte * Power(256, @count)) SET @count = @count + 1 IF (@count = 2) BEGIN SET @nchar = 0 SET @count = 0 SET @gather = 0 SET @nchar = 0 INSERT #errors VALUES (@errNumber, @errState, @errLevel, @errMessage, @errInstance, @errProcedure, @errLine) END GOTO Start END NextRow: FETCH NEXT FROM error_cursor INTO @dbccrow END CLOSE error_cursor DEALLOCATE error_cursor SELECT top 1 @errMessage=errMessage FROM #errors END' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__outputbuffer: -- =========================================================== sp__outputbuffer1 select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__outputbuffer1',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080923 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__outputbuffer1') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__outputbuffer1') with nowait goto skip_sp__outputbuffer1 end if @ver>080923 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__outputbuffer1') with nowait goto skip_sp__outputbuffer1 end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__outputbuffer1') with nowait if exists( select top 1 null from sys.objects where name='sp__outputbuffer1' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__outputbuffer1] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080923\S.Zaglio: used to get complete error description of @@error t:begin declare @s nvarchar(2000) exec(''truncate table_test'') exec sp__outputbuffer @s out print @s end */ CREATE PROCEDURE sp__outputbuffer1 @errmsg nvarchar(500) OUTPUT AS DECLARE @dbccrow nchar(77), @msglen int, @lenstr nchar(2), @sql nvarchar(2000), @s tinyint -- Catch the output buffer. CREATE TABLE #DBCCOUT (col1 nchar(77) NOT NULL) INSERT INTO #DBCCOUT EXEC (''DBCC OUTPUTBUFFER(@@spid)'') -- Set up a cursor over the table. We skip the first -- row, because there is nothing of interest. DECLARE error_cursor CURSOR STATIC FORWARD_ONLY FOR SELECT col1 FROM #DBCCOUT WHERE left(col1, 8) <> replicate(''0'', 8) ORDER BY col1 -- Init variable, and open cursor. SELECT @errmsg = '''' OPEN error_cursor FETCH NEXT FROM error_cursor INTO @dbccrow -- On this first row we find the length. SELECT @lenstr = substring(@dbccrow, 15, 2) -- Convert hexstring to int SELECT @sql = ''SELECT @int = convert(int, 0x00'' + @lenstr + '')'' EXEC sp_executesql @sql, N''@int int OUTPUT'', @msglen OUTPUT -- @s is where the ntext part of the buffer starts. SELECT @s = 62 -- Now assemble rest of string. WHILE @@FETCH_STATUS = 0 AND datalength(@errmsg) - 1 < 2 * @msglen BEGIN SELECT @errmsg = @errmsg + substring(@dbccrow, @s + 1, 1) + substring(@dbccrow, @s + 3, 1) + substring(@dbccrow, @s + 5, 1) + substring(@dbccrow, @s + 7, 1) + substring(@dbccrow, @s + 9, 1) + substring(@dbccrow, @s + 11, 1) + substring(@dbccrow, @s + 13, 1) + substring(@dbccrow, @s + 15, 1) FETCH NEXT FROM error_cursor INTO @dbccrow END CLOSE error_cursor DEALLOCATE error_cursor -- Now chop first character which is the length, and cut after end. SELECT @errmsg = substring(@errmsg, 2, @msglen)' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__outputbuffer1: -- ================================================================== sp__paging select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__paging',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091012 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__paging') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__paging') with nowait goto skip_sp__paging end if @ver>091012 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__paging') with nowait goto skip_sp__paging end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__paging') with nowait if exists( select top 1 null from sys.objects where name='sp__paging' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__paging] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091012\s.zaglio: show a table paged as in web c:from http://snipplr.com/view/112/sqlserver-2000-tsql-stored-procedure-for-providing-paginated-results/ t:sp__paging @tables=''[sysobjects]'',@pk=''[sysobjects].id'',@sort=''id'',@pagenumber=1,@pagesize=5 */ CREATE PROCEDURE sp__paging ( @TABLES nvarchar(1000), @PK nvarchar(100), @JoinStatements nvarchar(1000)='''', @FIELDS nvarchar(4000) = ''*'', @Filter nvarchar(4000) = ''1=1'', @Sort nvarchar(200) = NULL, @PageNumber int = 1, @PageSize int = 10, @TotalRec int =0 Output, @GROUP nvarchar(1000) = NULL ) AS /* Created by Kashif Akram Email Muhammad_kashif@msn.com The publication rights are reserved You can use this procedure with out removing these comments */ DECLARE @strPageSize nvarchar(50) DECLARE @strStartRow nvarchar(50) SET @strPageSize = CAST(@PageSize AS nvarchar(50)) SET @strStartRow = CAST(((@PageNumber - 1)*@PageSize + 1) AS nvarchar(50)) --set @PK ='' tbl_Items.ItemID '' CREATE TABLE #PageTable (PID bigint primary key IDENTITY (1, 1) , UID int) CREATE TABLE #PageIndex (UID int) /* CREATE UNIQUE CLUSTERED INDEX [PK_tbl_PageTable] ON #PageTable (PID) */ CREATE INDEX [PK_tbl_PageIndex] ON #PageIndex (UID) --''SELECT '' + @Fields + '' FROM '' + @Tables + '''' + @JoinStatements +'' WHERE '' + @strSortColumn + @operator + '' @SortColumn '' + @strSimpleFilter + '' '' + @strGroup + '' ORDER BY '' + @Sort + '' DESC '' exec ('' set rowcount 0 insert into #pageTable(UID) SELECT '' + @PK + '' FROM '' + @TABLES + '' '' + @JoinStatements +'' WHERE '' + @Filter + '' '' + @GROUP + '' ORDER BY '' + @Sort + '' DECLARE @SortColumn int SET ROWCOUNT ''+ @strStartRow +'' select @SortColumn=PID from #PageTable --option (keep plan) print @SortColumn SET ROWCOUNT ''+ @strPageSize +'' insert into #pageIndex select UID from #PageTable where PID >= @SortColumn -- option (keep plan) SELECT '' + @FIELDS + '' FROM '' + @TABLES + '' '' + @JoinStatements +'' WHERE '' + @Filter + '' and ''+ @PK + '' in (Select UID from #pageIndex)'' + @GROUP + '' ORDER BY '' + @Sort + '' '' ) SELECT @TotalRec=count(*) FROM #pageTable DROP TABLE #PageTable DROP TABLE #PageIndex RETURN' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__paging: -- ============================================================== sp__parse_date select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__parse_date',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110213 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__parse_date') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__parse_date') with nowait goto skip_sp__parse_date end if @ver>110213 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__parse_date') with nowait goto skip_sp__parse_date end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__parse_date') with nowait if exists( select top 1 null from sys.objects where name='sp__parse_date' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__parse_date] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility todo: finish all tests and add more r:110213\s.zaglio: parse a formatted string date t: sp__parse_date 13,@dbg=1 sp__parse_date ''13 20.30'',@dbg=1 sp__parse_date -1,@dbg=1 sp__parse_date ''-1 00.00'',@dbg=1 sp__parse_date ''-1 0'',@dbg=1 -- todo: yersterday at midnight sp__parse_date ''-1 0.0'',@dbg=1 -- todo: yersterday at midnight sp__parse_date ''-1 -1'',@dbg=1 -- todo: yersterday one month ago */ create proc sp__parse_date @dates nvarchar(64) = null, @date datetime = null out, @lng sysname = null, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- ========================================================= param formal chk == if @dates is null goto help -- ============================================================== declaration == declare @n int,@day int,@tk1 sysname,@tk2 sysname,@tk3 sysname,@tk4 sysname -- =========================================================== initialization == -- ======================================================== second params chk == -- ===================================================================== body == if isnull(@lng,'''')!='''' begin set language @lng if @@error!=0 select @ret=-1 if @ret!=0 goto ret end if isdate(@dates)=1 begin select @date=convert(datetime,@dates) goto ret end if isnumeric(@dates)=1 begin select @day=convert(int,@dates) if @day>0 begin select @date=getdate() select @date=@date-day(@date)+@day end else select @date=getdate()+@day goto dispose end select @n=dbo.fn__str_count(@dates,'''') select @tk1=dbo.fn__str_at(@dates,'''',1) select @tk2=dbo.fn__str_at(@dates,'''',2) select @tk3=dbo.fn__str_at(@dates,'''',3) select @tk4=dbo.fn__str_at(@dates,'''',4) if isnumeric(@tk1)=1 and (charindex(''.'',@tk2)>0 or charindex('':'',@tk2)>0) begin select @day=convert(int,@tk1) if @day>0 begin select @date=getdate() select @date=@date-day(@date)+@day end else select @date=getdate()+@day select @dates=convert(sysname,@date,126) select @dates=substring(@dates,1,charindex(''T'',@dates)) -- iso(126): yyyy-mm-ddThh:mm:ss.mmm select @tk2=replace(@tk2,''.'','':'') select @n=dbo.fn__str_count(@dates,'':'') if @n=1 select @tk2=@tk2+'':00.000'' select @dates=@dates+@tk2 select @date=convert(datetime,@dates,126) goto dispose end -- day hour dispose: if @dbg=1 exec sp__printf ''dates=%s, date=%s, tk1=%s tk2=%s'',@dates,@date,@tk1,@tk2 goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope parse a formatted string date Parameters @dates date in string(input) format @date the converted date @lng language (default current; see set language or sys.syslanguages) return a non zero value if an error Examples value convertion "full iso" considered 13 considered current day 13 20.30 day 13 of current month/year, hour 20.30 13 20:30 day 13 of current month/year, hour 20.30 -1 today less one day '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__parse_date' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__parse_date: -- ========================================================== sp__parse_url_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__parse_url_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130906.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__parse_url_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__parse_url_test') with nowait goto skip_sp__parse_url_test end if @ver>130906.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__parse_url_test') with nowait goto skip_sp__parse_url_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__parse_url_test') with nowait if exists( select top 1 null from sys.objects where name='sp__parse_url_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__parse_url_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:url,uri,parse,path,web,internet v:130906.1000\s.zaglio: test and show use of fn__parse_url t:sp__parse_url_test */ CREATE proc sp__parse_url_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @urls table(url sysname) declare @url sysname -- =========================================================== initialization == insert @urls -- select ''protocol://nomehost<:port>'' union select ''svn://lupin/SOURCES\*.vb'' union select ''file:///C:/Documents%20and%20Settings/ste...'' union select ''file://///svr/share/dir/sdir/file.ext'' union select ''file://svr/share/dir/sdir/file.ext'' union select ''https://sap.mymeetingroom.com/?content...'' union select ''http://maps.google.com/maps/api/geocode/xml?sensor=false&address=8+soratino,+italy'' union select ''https//sap.mymeetingroom.com/?content...'' union select ''ftp://pwd:usr@site.org'' union select ''\\svr\share\dir\file.ext'' union select ''\\pwd:uid@svr\share\dir\file.ext'' union select ''c:\share\dir\file.ext'' -- ======================================================== second params chk == -- =============================================================== #tbls init == select top 0 cast(null as sysname) status,* into #tmp from dbo.fn__parse_url('''',default) -- ===================================================================== body == declare cs cursor local for select url from @urls open cs while 1=1 begin fetch next from cs into @url if @@fetch_status!=0 break begin try insert #tmp select ''ok'',* from fn__parse_url(@url,default) end try begin catch insert #tmp(status,url) select ''ko:''+error_message(),@url end catch end -- cursor cs close cs deallocate cs update #tmp set status=''ko'' where normalized is null select * from #tmp order by status -- ================================================================== dispose == dispose: drop table #tmp -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test fn__parse_url Parameters [param] [desc] @opt options (not used) @dbg not used '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__parseurl_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__parse_url_test: -- ==================================================================== sp__perf select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130707.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf') with nowait goto skip_sp__perf end if @ver>130707.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf') with nowait goto skip_sp__perf end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf') with nowait if exists( select top 1 null from sys.objects where name='sp__perf' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130707.1000\s.zaglio: added info about wait events v:130222\s.zaglio: added perf code in comments for future implementation v:120811\s.zaglio: added comment about WMI v:120220.1748\s.zaglio: added io perf v:120104\s.zaglio: re-enabled record v:111011\s.zaglio: a remake v:111005\s.zaglio: added @waitfor v:110926\s.zaglio: refine d:110926\s.zaglio: sp__perf_top25 v:100129\s.zaglio: print top 25 heavy processes t:sp__perf_old t:sp__perf @opt=''record'' select * from tmp_stat_perf order by readed desc t:sp_monitor */ CREATE proc sp__perf @waitfor sysname=null, @opt sysname=null as begin set nocount on declare @proc sysname,@ret int,@err int select @err=0,@ret=0,@proc=object_name(@@procid), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if not @waitfor is null goto err_prm /* 130221\s.zaglio: query useful to detect perf. problem -- select wait_type,count(*) n from sys.dm_exec_requests group by wait_type order by count(*) desc -- select * from sys.dm_exec_requests -- SELECT COUNT(*) AS ''Number of waiting tasks'' FROM sys.dm_os_waiting_tasks; -- SELECT COUNT(*) AS ''Number of threads'' FROM sys.dm_os_waiting_tasks WHERE wait_type <> ''THREADPOOL''; -- SELECT CAST(wait_type AS VARCHAR(30)) AS ''Waiting task'', COUNT (*) AS ''Number of waiting tasks'' FROM sys.dm_os_waiting_tasks GROUP BY wait_type ORDER BY ''Number of waiting tasks'' DESC; -- EXEC sys.sp_configure N''max degree of parallelism'' -- select * from sys.dm_os_nodes -- mssql2k12 -- SELECT waiting_task_address AS ''Task address'',session_id AS ''Session'',exec_context_id AS ''Context'',wait_duration_ms AS ''Wait in millsec'',CAST(wait_type AS VARCHAR(30)) AS ''Type'',resource_address AS ''Resource address'',blocking_task_address AS ''Blocking task'',blocking_session_id AS ''Blocking session'',CAST(resource_description AS VARCHAR(30)) AS ''Resource'' FROM sys.dm_os_waiting_tasks WHERE wait_duration_ms > 20 AND wait_type LIKE ''%PAGEIOLATCH%''; -- sp__perf_monitor -- SELECT resource_address AS ''Resource Bottleneck'',COUNT (*) AS ''# of bottlenecks'' FROM sys.dm_os_waiting_tasks WHERE resource_address <> 0 GROUP BY resource_address ORDER BY ''# of bottlenecks'' DESC; -- select ''UPDATE STATISTICS ''+name+'' WITH fullscan'' from sysobjects where xtype=''U'' -- http://blogs.msdn.com/b/cindygross/archive/2011/01/28/the-ins-and-outs-of-maxdop.aspx -- the phisical cpu count is wrong on xeon that has 1 processor/package 4 cpus and 4 threads but 1 x cpu -- select cpu_count as [logical cpus], hyperthread_ratio as hyperthread_ratio,cpu_count/hyperthread_ratio as physical_cpu_count,physical_memory_in_bytes/1048576 as physical_memory_in_mb from sys.dm_os_sys_info -- if is mssql2k8 -- https://www.simple-talk.com/sql/performance/investigating-sql-server-2008-wait-events-with-xevents/ -- ms resource about perf problems -- http://technet.microsoft.com/en-us/library/cc966540.aspx -- simple and correct cpu use calc, tested and compared with visual graphics declare @cpu_busy int, @idle int, @io_busy int select @cpu_busy = @@cpu_busy, @idle = @@idle , @io_busy=@@io_busy waitfor delay ''000:00:01'' select (@@cpu_busy - @cpu_busy)/((@@idle - @idle + @@cpu_busy - @cpu_busy) *1.00) *100 as ''cpu'', (@@io_busy - @io_busy)/((@@idle - @idle + @@io_busy - @io_busy) *1.00) *100 as ''io'' -- Total waits are wait_time_ms (high signal waits indicates CPU pressure) -- if pct signal wait > 10%, means that more cpu are required SELECT CAST(100.0 * SUM(signal_wait_time_ms) / SUM(wait_time_ms) AS NUMERIC(20,2)) AS [%signal (cpu) waits] , CAST(100.0 * SUM(wait_time_ms - signal_wait_time_ms) / SUM(wait_time_ms) AS NUMERIC(20, 2)) AS [%resource waits]FROM sys.dm_os_wait_stats ; -- Isolate top waits for server instance since last restart -- or statistics clear WITH Waits AS ( SELECT wait_type , wait_time_ms / 1000. AS wait_time_s , 100. * wait_time_ms / SUM(wait_time_ms) OVER ( ) AS pct , ROW_NUMBER() OVER ( ORDER BY wait_time_ms DESC ) AS rn FROM sys.dm_os_wait_stats WHERE wait_type NOT IN ( ''CLR_SEMAPHORE'', ''LAZYWRITER_SLEEP'', ''RESOURCE_QUEUE'', ''SLEEP_TASK'', ''SLEEP_SYSTEMTASK'', ''SQLTRACE_BUFFER_FLUSH'', ''WAITFOR'', ''LOGMGR_QUEUE'', ''CHECKPOINT_QUEUE'', ''REQUEST_FOR_DEADLOCK_SEARCH'', ''XE_TIMER_EVENT'', ''BROKER_TO_FLUSH'', ''BROKER_TASK_STOP'', ''CLR_MANUAL_EVENT'', ''CLR_AUTO_EVENT'', ''DISPATCHER_QUEUE_SEMAPHORE'', ''FT_IFTS_SCHEDULER_IDLE_WAIT'', ''XE_DISPATCHER_WAIT'', ''XE_DISPATCHER_JOIN'' ) ) SELECT W1.wait_type , CAST(W1.wait_time_s AS DECIMAL(12, 2)) AS wait_time_s , CAST(W1.pct AS DECIMAL(12, 2)) AS pct , CAST(SUM(W2.pct) AS DECIMAL(12, 2)) AS running_pct FROM Waits AS W1 INNER JOIN Waits AS W2 ON W2.rn <= W1.rn GROUP BY W1.rn , W1.wait_type , W1.wait_time_s , W1.pct HAVING SUM(W2.pct) - W1.pct < 95 ; -- percentage threshold -- Recovery model, log reuse wait description, log file size, -- log usage size and compatibility level for all databases on instance SELECT db.[name] AS [Database Name] , db.recovery_model_desc AS [Recovery Model] , db.log_reuse_wait_desc AS [Log Reuse Wait Description] , ls.cntr_value AS [Log Size (KB)] , lu.cntr_value AS [Log Used (KB)] , CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT) AS DECIMAL(18,2)) * 100 AS [Log Used %] , db.[compatibility_level] AS [DB Compatibility Level] , db.page_verify_option_desc AS [Page Verify Option] FROM sys.databases AS db INNER JOIN sys.dm_os_performance_counters AS lu ON db.name = lu.instance_name INNER JOIN sys.dm_os_performance_counters AS ls ON db.name = ls.instance_name WHERE lu.counter_name LIKE ''Log File(s) Used Size (KB)%'' AND ls.counter_name LIKE ''Log File(s) Size (KB)%'' ; ---- average stalls per read, write and total ---- adding 1.0 to avoid division by zero errors select db_name(database_id) db, file_id ,io_stall_read_ms ,num_of_reads ,cast(io_stall_read_ms/(1.0+num_of_reads) as numeric(10,1)) as ''avg_read_stall_ms'' ,io_stall_write_ms ,num_of_writes ,cast(io_stall_write_ms/(1.0+num_of_writes) as numeric(10,1)) as ''avg_write_stall_ms'' ,io_stall_read_ms + io_stall_write_ms as io_stalls ,num_of_reads + num_of_writes as total_io ,cast((io_stall_read_ms+io_stall_write_ms)/(1.0+num_of_reads + num_of_writes) as numeric(10,1)) as ''avg_io_stall_ms'' from sys.dm_io_virtual_file_stats(null,null) order by avg_io_stall_ms desc -- transactions x second declare @n int select @n=cntr_value from sys.dm_os_performance_counters where counter_name = ''transactions/sec'' and rtrim(object_name) like ''%:databases'' and instance_name = db_name() waitfor delay ''00:00:01'' select (cntr_value-@n)/1 from sys.dm_os_performance_counters where counter_name = ''transactions/sec'' and rtrim(object_name) like ''%:databases'' and instance_name = db_name() */ /* DBCC SQLPERF (Waitstats) PAGELATCH_EX indicated waits for physical I/O CXPACKET indicates waits for parallel processes to complete. NETWORKIO indicates waits for Network I/O For NETWORKIO, use perfmon to determine the workload and if there is sufficient thruput available. For CXPACKET, if this is primarily OLTP transactions, suggest disabling parallelism (max degree of 1 ). For PAGELATCH_EX, suggest you gather database file I/O statistics on a regular basis to determine if there is a disk resource problem: select db_name(dbid) db,IoStallMS / ( NumberReads + NumberWrites ) as MsPerIo,* from :: fn_virtualfilestats(default,default) order by IoStallMS / ( NumberReads + NumberWrites ) desc The statistics are since the SQL Server was started, so you will need to determine the changes between two sets of statistics yourself. MsPerIo should be under 8 and under 4 is desirable. Also use perfmon to check the disk queue length. I second Grant Fritchey''s recommendation to run a trace. There are MS provided tools to analyze the traces that are not very friendly (obtuse command line switches ) but the results are incredibly useful and almost impossible to produce manually. http://support.microsoft.com/kb/944837 Consider this http://thomaslarock.com/2011/01/wmi-code-creator/ about WMI but it does not work in production and return an absurd value. */ -- 5/6/2003 sp - sqlhogs 2.0 -- modify below to proper number of processors -- (hyperthreaded and multi-core count so probably just see how many show in task mgr) -- 2/2/07 sp - modified to sum for ecids per spid, as opposed to just showing ecit=0 -- grabs two snapshots from sysperfinfo and presents a delta between them -- to estimate sql server usage. declare @icpucount int, @cpu_busy bigint, @idle_busy bigint,@io_busy bigint, @cpu numeric(32,2), @idle numeric(32,2),@io numeric(32,2), @secfromstart numeric (18,2), @dt datetime,@s int, @record bit select @record=charindex(''|record|'',@opt), @dt=getdate(), @secfromstart = datediff(s, ( select top 1 login_time -- start time of the instance from master..sysprocesses where cmd=''lazy writer'' ), getdate() ) exec('' create proc #iostats_fill as insert #iostats select * from ( select getdate() as capture_time, --virtual file latency readlatency = case when num_of_reads = 0 then 0 else (io_stall_read_ms / num_of_reads) end, writelatency = case when num_of_writes = 0 then 0 else (io_stall_write_ms / num_of_writes) end, latency = case when (num_of_reads = 0 and num_of_writes = 0) then 0 else (io_stall / (num_of_reads + num_of_writes)) end, --avg bytes per iop avgbperread = case when num_of_reads = 0 then 0 else (num_of_bytes_read / num_of_reads) end, avgbperwrite = case when io_stall_write_ms = 0 then 0 else (num_of_bytes_written / num_of_writes) end, avgbpertransfer = case when (num_of_reads = 0 and num_of_writes = 0) then 0 else ((num_of_bytes_read + num_of_bytes_written) / (num_of_reads + num_of_writes)) end, left (mf.physical_name, 2) as drive, db_name (vfs.database_id) as db, --vfs.*, substring( mf.physical_name, len(mf.physical_name)- charindex(''''\'''',reverse(mf.physical_name))+2, 100 ) as file_name, num_of_writes+num_of_reads nwr -- select * from sys.dm_io_virtual_file_stats (null,null) as vfs join sys.master_files as mf on vfs.database_id = mf.database_id and vfs.file_id = mf.file_id ) vfs where 1=1 and latency>50 -- vfs.file_id = 2 -- log files -- order by latency desc -- order by readlatency desc -- order by writelatency desc; '') -- drop table #iostats create table #iostats ( capture_time datetime, readlatency bigint null, writelatency bigint null, latency bigint null, avgbperread bigint null, avgbperwrite bigint null, avgbpertransfer bigint null, drive nvarchar(2) null, db nvarchar(128) null, file_name nvarchar(100) null, nwr bigint null ) -- get number of processors /* select @icpucount=cpu_count / hyperthread_ratio as physical_cpu_sockets from sys.dm_os_sys_info ; */ create table #numprocs ( id int, colname varchar(128), iv int, cv varchar(128) ) exec(''exec #iostats_fill'') select @waitfor=''%''+@waitfor+''%'' while (1=1) begin insert #numprocs exec master..xp_msver select @icpucount = iv from #numprocs where colname like ''%processorcount%'' drop table #numprocs -- dbcc inputbuffer(spid) - shows the command that was run -- spid = sql server process id. -- kpid = windows thread id. the thread id shows the kpid for a given sql server thread. -- blocked = spid of the blocking process. -- waittime = ms. -- dbid = database id -- uid = user id -- cpu = ms -- physical io = physical reads and writes -- memusage = number of pages in proc cache for this spid -- last_batch = time of last exec or stored proc -- ecid = identifies subthreads within a spid -- get the two snapshots, 1 second apart. -- exclude user = system. select 1 as snapnum, spid, kpid, blocked, waittime, dbid, uid, cpu, physical_io, memusage, login_time, last_batch, ecid, status, hostname, program_name, cmd, net_address, loginame, getdate() as snaptime, sql_handle,stmt_start,stmt_end,lastwaittype,waitresource into #snapshot from master..sysprocesses where uid >= 0 select @cpu_busy = @@cpu_busy, @idle_busy = @@idle,@io_busy=@@io_busy waitfor delay ''00:00:01'' -- sp__perf select @cpu= (cast(@@cpu_busy as float)- @cpu_busy)/ ((@@idle - @idle_busy + @@cpu_busy - @cpu_busy+0.001) *1.00) *100.0, @io= (cast(@@io_busy as float)- @io_busy)/ 1000.00 *100.0, @idle= (cast(@@io_busy as float)- @io_busy)/ ((@@idle - @idle_busy + @@io_busy - @io_busy+0.001) *1.00) *100.0 insert into #snapshot select 2 as snapnum, spid, kpid, blocked, waittime, dbid, uid, cpu, physical_io, memusage, login_time, last_batch, ecid, status, hostname, program_name, cmd, net_address, loginame, getdate() as snaptime, sql_handle,stmt_start,stmt_end,lastwaittype,waitresource from master..sysprocesses where uid >= 0 -- join the two snapshots, dropping ecid''s that were missing from one or the other. -- just do the columns that require a delta for performance. select s1.spid as s1_spid, s1.ecid as s1_ecid, s1.waittime as s1_waittime, s1.cpu as s1_cpu, s1.physical_io as s1_physical_io, s1.snaptime as s1_snaptime, s2.waittime as s2_waittime, s2.cpu as s2_cpu, s2.physical_io as s2_physical_io, s2.snaptime as s2_snaptime into #snapboth from #snapshot as s1 join #snapshot as s2 on s1.spid = s2.spid and s1.ecid = s2.ecid and s1.snapnum = 1 and s2.snapnum = 2 -- get the difference between the 2 snapshots, ms per ecid -- this is ( / 1000 * 100 ). select s1_spid as spid, s1_ecid as ecid, sum( s2_waittime - s1_waittime ) as waitmsperecid, sum( s2_cpu - s1_cpu ) as cpumsperecid, sum( s2_physical_io - s1_physical_io ) as deltaioperecid into #perfdeltaperecid from #snapboth group by s1_spid, s1_ecid -- and sum those across per spid. select spid, sum( waitmsperecid ) as waitms, sum( cpumsperecid ) as cpums, sum( deltaioperecid ) as deltaio into #perfdelta from #perfdeltaperecid group by spid -- show the results for the cpu hogs. -- cpu conversion is ms to sec and then to percent / cpus. select top 5 @dt as readed, @cpu [scpu%],@io [io%], @idle [io_idle%], convert( integer, pd.cpums * 0.001 * 100.0 / @icpucount ) as [pcpu%], pd.deltaio as [dIO], lcks.n dls, pd.spid, ss.kpid, convert( varchar(16), ss.loginame ) as username, case when ss.program_name like ''sqlagent - tsql jobstep (job %'' then ( select top 1 j.name from msdb..sysjobs j where rtrim(ltrim(dbo.fn__str_between(ss.program_name,''job '','' :'',default))) = dbo.fn__hex(convert(varbinary,job_id)) ) else object_name((select top 1 objectid from ::fn_get_sql(ss.sql_handle))) end obj, substring((select top 1 text from ::fn_get_sql(ss.sql_handle)), coalesce(nullif(case ss.stmt_start when 0 then 0 else ss.stmt_start / 2 end, 0), 1), case (case ss.stmt_end when -1 then -1 else ss.stmt_end / 2 end) when -1 then datalength((select top 1 text from ::fn_get_sql(ss.sql_handle))) else ((case ss.stmt_end when -1 then -1 else ss.stmt_end / 2 end) - (case ss.stmt_start when 0 then 0 else ss.stmt_start / 2 end) ) end ) as [sql], ss.cmd, convert( varchar(15), ss.hostname ) as host, convert( varchar(15), ss.program_name ) as program, ( select name from master..sysdatabases where dbid = ss.dbid ) as db, ss.status, ss.login_time, ss.last_batch, ss.net_address,lastwaittype lwr,waitresource wr into #out from #perfdelta as pd join #snapshot as ss on pd.spid = ss.spid and ss.ecid = 0 and ss.snapnum = 1 left join ( select count(*) as n, resource_database_id dbid from master.sys.dm_tran_locks group by resource_database_id ) lcks on lcks.dbid=ss.dbid where cpums > 5 and pd.spid!=@@spid -- and pd.spid>50 -- to exclude system spid order by (cpums+deltaio)/2 desc -- output result if @record=0 begin select * from #out exec(''exec #iostats_fill'') -- query 5: compute the total number of reads and writes. select t2.readlatency,t2.writelatency,t2.latency, t2.avgbperread,t2.avgbperwrite,t2.avgbpertransfer, t2.db,t2.drive,t2.file_name from #iostats t1 join #iostats t2 on t1.db=t2.db and t1.file_name=t2.file_name and t1.capture_time < t2.capture_time where t2.nwr - t1.nwr > 0 order by latency desc end -- record = 0 else begin if object_id(''tmp_stat_perf'') is null select identity(int,1,1) id,* into tmp_stat_perf from #out else insert tmp_stat_perf select * from #out end -- record break -- one day will re-implement waitfor end -- while drop proc #iostats_fill drop table #perfdeltaperecid drop table #perfdelta drop table #snapboth drop table #snapshot /* -- turn the raw statistics into rates select cast(cast(@@total_read as numeric (18,2))/@secfromstart as numeric (18,2)) as [reads/sec] , cast(cast(@@total_write as numeric (18,2))/@secfromstart as numeric (18,2)) as [writes/sec] , cast(@@io_busy * cast(@@timeticks as numeric(18,2))/10000.0/@secfromstart as numeric (18,2)) as [percent i/o time] */ goto help err_prm: exec @ret=sp__err ''parameter gived for compatibility but not working'',@proc goto ret help: exec sp__printf '' Scope get processes performance with info Parameters @waitfor (TODO) wait until this word appear in the sql code or obj name @opt options record store data into table tmp_stat_perf Fields description scpu%: is the whole server cpu usage pcpu%: is the single process cpu usage dIO: is the delta IO milliseconds dls: database locks status: Process ID status. The possible values are: dormant SQL Server is resetting the session. running The session is running one or more batches. When Multiple Active Result Sets (MARS) is enabled, a session can run multiple batches. For more information, see Using Multiple Active Result Sets (MARS). background The session is running a background task, such as deadlock detection. rollback The session has a transaction rollback in process. pending The session is waiting for a worker thread to become available. runnable The task in the session is in the runnable queue of a scheduler while waiting to get a time quantum. spinloop The task in the session is waiting for a spinlock to become free. suspended The session is waiting for an event, such as I/O, to complete. lwr (lastwaittype): CXPACKET Often indicates nothing more than that certain queries are executing with parallelism; CXPACKET waits in the server are not an immediate sign of problems, although they may be the symptom of another problem, associated with one of the other high value wait types in the instance. SOS_SCHEDULER_YIELD The tasks executing in the system are yielding the scheduler, having exceeded their quantum, and are having to wait in the runnable queue for other tasks to execute. This may indicate that the server is under CPU pressure. THREADPOOL A task had to wait to have a worker bound to it, in order to execute. This could be a sign of worker thread starvation, requiring an increase in the number of CPUs in the server, to handle a highly concurrent workload, or it can be a sign of blocking, resulting in a large number of parallel tasks consuming the worker threads for long periods. LCK_* These wait types signify that blocking is occurring in the system and that sessions have had to wait to acquire a lock of a specific type, which was being held by another database session. This problem can be investigated further using, for example, the information in the sys.dm_db_index_operational_stats. PAGEIOLATCH_*, IO_COMPLETION, WRITELOG These waits are commonly associated with disk I/O bottlenecks, though the root cause of the problem may be, and commonly is, a poorly performing query that is consuming excessive amounts of memory in the server. PAGEIOLATCH_* waits are specifically associated with delays in being able to read or write data from the database files. WRITELOG waits are related to issues with writing to log files. These waits should be evaluated in conjunction with the virtual file statistics as well as Physical Disk performance counters, to determine if the problem is specific to a single database, file, or disk, or is instance wide. PAGELATCH_* Non-I/O waits for latches on data pages in the buffer pool. A lot of times PAGELATCH_* waits are associated with allocation contention issues. One of the best-known allocations issues associated with PAGELATCH_* waits occurs in tempdb when the a large number of objects are being created and destroyed in tempdb and the system experiences contention on the Shared Global Allocation Map (SGAM), Global Allocation Map (GAM), and Page Free Space (PFS) pages in the tempdb database. LATCH_* These waits are associated with lightweight short-term synchronization objects that are used to protect access to internal caches, but not the buffer cache. These waits can indicate a range of problems, depending on the latch type. Determining the specific latch class that has the most accumulated wait time associated with it can be found by querying the sys.dm_os_latch_stats DMV. ASYNC_NETWORK_IO This wait is often incorrectly attributed to a network bottleneck. In fact, the most common cause of this wait is a client application that is performing row-by-row processing of the data being streamed from SQL Server as a result set (client accepts one row, processes, accepts next row, and so on). Correcting this wait type generally requires changing the client-side code so that it reads the result set as fast as possible, and then performs processing. '' ret: return @ret end -- sp__perf' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf: -- ============================================================== sp__perf_daily select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf_daily',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091216 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf_daily') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf_daily') with nowait goto skip_sp__perf_daily end if @ver>091216 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf_daily') with nowait goto skip_sp__perf_daily end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf_daily') with nowait if exists( select top 1 null from sys.objects where name='sp__perf_daily' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf_daily] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091216\s.zaglio:added @@servername v:091018\s.zaglio: Statistic of SQL-Server - System parameters for dynamic collection. @@cpu_busy/1000 - Returns the time in seconds that the CPU has spent working since SQL Server was last started. @@io_busy/1000 - Returns the time in seconds that SQL Server has spent performing input and output operations since it was last started. @@idle/1000 - Returns the time in seconds that SQL Server has been idle since last started. @@pack_received - Returns the number of input packets read from the network by SQL Server since last started. @@pack_sent - Returns the number of output packets written to the network by SQL Server since last started. @@packet_errors - Returns the number of network packet errors that have occurred on SQL Server connections since SQL Server was last started. @@connections - Returns the number of connections, or attempted connections, since SQL Server was last started. @@total_read - Returns the number of disk reads (not cache reads) by SQL Server since last started. @@total_write - Returns the number of disk writes by SQL Server since last started. @@total_errors - Returns the number of disk read/write errors encountered by SQL Server since last started. */ /* Daily Version. Output - Table TBL_SERVERSTATISTICS. A Table include Row per run a Procedure,except Saturday. Sunday statistic include Saturday. In the table TBL_SERVERSTATISTICS_PRIOR save SQL Server statistic since last started. Delete history statistic rows - more than one year. Return Code: 1 - BAD, 0 - GOOD. Author - Mushkatin Vadim,DBA,Israel. Created - 09/03/2003. -- select * from TBL_SERVERSTATISTICS -- select * from TBL_SERVERSTATISTICS_PRIOR -- sp__dir ''*tbl*'' */ CREATE PROCEDURE [dbo].[sp__perf_daily] ( @BIT_DELETE_RESULTS BIT = 0 ) AS SET NOCOUNT ON Declare @weekday int , @count int , @sql_started datetime Declare @id_prior int , @sampletime_prior datetime , @cpu_busy_prior INT , @io_busy_prior INT , @idle_prior INT , @pack_received_prior INT , @pack_send_prior INT , @packed_errors_prior INT , @connections_prior INT , @total_read_prior INT , @total_write_prior INT , @total_errors_prior INT ------------------------------------------ Set @sql_started = ( select login_time from master..sysprocesses where spid = 1 ) Set @weekday = (select DATEPART ( weekday , getdate() )) IF @weekday <> 7 BEGIN ------------------------------------------ IF OBJECT_ID(''TBL_SERVERSTATISTICS_PRIOR'') IS NULL CREATE TABLE TBL_SERVERSTATISTICS_PRIOR ( [ID] INT IDENTITY, SQL_Started datetime, SAMPLETIME datetime, cpu_busy INT, io_busy INT, idle INT, pack_received INT, pack_send INT, packed_errors INT, connections INT, total_read INT, total_write INT, total_errors INT, svr sysname) Set @count = ( select count(*) from TBL_SERVERSTATISTICS_PRIOR ) If @count = 0 Begin TRUNCATE TABLE TBL_SERVERSTATISTICS_PRIOR INSERT INTO TBL_SERVERSTATISTICS_PRIOR select @sql_started,getdate(),@@cpu_busy/1000,@@io_busy/1000, @@idle /1000, @@pack_received ,@@pack_sent, @@packet_errors , @@connections , @@total_read , @@total_write , @@total_errors,@@servername End IF OBJECT_ID(''TBL_SERVERSTATISTICS'') IS NOT NULL Begin IF @BIT_DELETE_RESULTS = 1 --Warning !!! TRUNCATE TABLE TBL_SERVERSTATISTICS End ELSE CREATE TABLE TBL_SERVERSTATISTICS ( [ID] INT IDENTITY, LastRunTIME datetime, SAMPLETIME datetime, cpu_busy INT, io_busy INT, idle INT, pack_received INT, pack_send INT, packed_errors INT, connections INT, total_read INT, total_write INT, total_errors INT, svr sysname) If exists ( select sampletime from TBL_SERVERSTATISTICS_PRIOR where id = 1 ) Set @sampletime_prior = (select sampletime from TBL_SERVERSTATISTICS_PRIOR where id = 1) Else Begin Print ''Not found data in table TBL_SERVERSTATISTICS_PRIOR.'' Return 1 End If @sql_started <= @sampletime_prior Begin Declare c_table_prior cursor for select cpu_busy, io_busy, idle, pack_received, pack_send,packed_errors, connections, total_read, total_write, total_errors FROM TBL_SERVERSTATISTICS_PRIOR where [id] = 1 open c_table_prior fetch next from c_table_prior into @cpu_busy_prior,@io_busy_prior,@idle_prior,@pack_received_prior,@pack_send_prior, @packed_errors_prior, @connections_prior, @total_read_prior, @total_write_prior, @total_errors_prior INSERT INTO TBL_SERVERSTATISTICS select @sampletime_prior,getdate(),@@cpu_busy/1000 - @cpu_busy_prior,@@io_busy/1000 - @io_busy_prior, @@idle/1000 - @idle_prior,@@pack_received - @pack_received_prior , @@pack_sent - @pack_send_prior , @@packet_errors - @packed_errors_prior , @@connections - @connections_prior , @@total_read - @total_read_prior, @@total_write - @total_write_prior, @@total_errors - @total_errors_prior, @@servername close c_table_prior deallocate c_table_prior END Else Begin Print ''Daily statistic Row not inserted because of REBOOT server.'' Print ''SQL Server started - '' + cast(@sql_started as nchar(17)) End --since SQL Server last started Truncate table TBL_SERVERSTATISTICS_PRIOR INSERT INTO TBL_SERVERSTATISTICS_PRIOR select @sql_started,getdate(),@@cpu_busy/1000 ,@@io_busy/1000, @@idle/1000 ,@@pack_received ,@@pack_sent , @@packet_errors ,@@connections , @@total_read,@@total_write, @@total_errors,@@servername END --Close First IF --Delete history statistic rows (more than one year) Delete From TBL_SERVERSTATISTICS Where SAMPLETIME < ( getdate() - 365 ) Return 0' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf_daily: -- =============================================================== sp__perf_info select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf_info',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100522.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf_info') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf_info') with nowait goto skip_sp__perf_info end if @ver>100522.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf_info') with nowait goto skip_sp__perf_info end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf_info') with nowait if exists( select top 1 null from sys.objects where name='sp__perf_info' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf_info] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,perf v:100522.1000\s.zaglio: list performance counters t:sp__perf_info "database","trans","total",@dbg=1 */ CREATE proc sp__perf_info @obj sysname = null, @cnt sysname = null, @inst sysname = null, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- ========================================================= param formal chk == -- ============================================================== declaration == declare @sql nvarchar(4000), @objects nvarchar(4000), @counters nvarchar(4000), @instances nvarchar(4000), @tbl sysname -- =========================================================== initialization == select @objects=''select distinct object_name as objects from %tbl% order by 1'' select @counters=''select distinct counter_name as counters from %tbl% order by 1'' select @instances=''select distinct instance_name as instances from %tbl% order by 1'' select @obj=isnull(@obj,''''), @cnt=isnull(@cnt,''''), @inst=isnull(@inst,'''') select @sql='' select * from %tbl% where 1=1 and object_name like ''''%%obj%%'''' and counter_name like ''''%%cnt%%'''' and instance_name like ''''%%inst%%'''' '' if dbo.fn__isMSSQL2K()=1 select @tbl=''sysperfinfo'' else select @tbl=''sys.dm_os_performance_counters'' exec sp__str_replace @objects out,''%tbl%'',@tbl exec sp__str_replace @counters out,''%tbl%'',@tbl exec sp__str_replace @instances out,''%tbl%'',@tbl exec sp__str_replace @sql out,''%tbl%|%obj%|%cnt%|%inst%'',@tbl,@obj,@cnt,@inst -- ======================================================== second params chk == if @obj='''' and @cnt='''' and @inst='''' goto help -- ===================================================================== body == if @dbg=1 exec sp__printsql @sql exec(@sql) goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope list performance counters Parameters @obj, Examples -- show total transactions sp__perf_info "database","trans","total" -- Counter: Recommended value SQLServer:Memory Manager\Memory Grants Pending:0 SQServer:Buffer Manager\Buffer Hit cache Ratio:>95% SQLServer:Buffer Manager\Page life Expectancy:>300 SQLServer:Buffer Manager\Free Pages:>300 SQLServer:Buffer Manager\Free list Stalls/Sec:0 Memory Grants Pending represents the total number of processes waiting for a workspace memory grant, a non-zero value indicates a memory problem Buffer Hit Cache Ratio represets the percentage of time SQL was able to get the page from buffer pool instead of having to do a hard read from disk Page Life Expectancy shows how long a data page stays in the buffer cache. 300 seconds is the industry-accepted threshold for this counter. Anything less than a 300-second average over an extended period of time tells you that the data pages are being flushed from memory too frequently and SQL has to do hard reads from disk fullfill requests, hard reads require CPU/lock resources etc. if there is a sudden drop in Page life expectancy then we need to check Checkpoints Pages/sec counter When a checkpoint occurs in the system, the dirty data pages in the buffer cache are flushed to disk, causing the Page life Expectancy value to drop. Free Pages represent the total number of pages on all free lists, this number in general should be above 300 the hight the better, a lower number would be ok if Free list stalls/sec is a zero value. Free list Stalls/Sec represents Number of requests per second that had to wait for a free page. if you have defined that your server is under memory pressure the second thing to do to check the components that consume the memory. -- list of objects, counters, instances -- '' exec sp__select_astext @objects,@header=1 exec sp__printf '''' exec sp__select_astext @counters,@header=1 exec sp__printf '''' exec sp__select_astext @instances,@header=1 select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__perf_info' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf_info: -- ============================================================ sp__perf_monitor select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf_monitor',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140109 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf_monitor') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf_monitor') with nowait goto skip_sp__perf_monitor end if @ver>140109 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf_monitor') with nowait goto skip_sp__perf_monitor end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf_monitor') with nowait if exists( select top 1 null from sys.objects where name='sp__perf_monitor' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf_monitor] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140109\s.zaglio:problem of cpu_ticks_in_ms in os 64bit r:110922\s.zaglio:sp__perf_monitor */ CREATE proc sp__perf_monitor @n tinyint = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @opt is null goto help -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit declare @ts_now bigint, @from datetime,@to datetime,@sql int,@idle int,@other int -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == /* - HIGH CPU ******* -- Isolate top waits for server instance WITH Waits AS ( SELECT wait_type, wait_time_ms / 1000. AS wait_time_s, 100. * wait_time_ms / SUM(wait_time_ms) OVER() AS pct, ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS rn FROM sys.dm_os_wait_stats WHERE wait_type NOT LIKE ''%SLEEP%'' ) SELECT W1.wait_type, CAST(W1.wait_time_s AS DECIMAL(12, 2)) AS wait_time_s, CAST(W1.pct AS DECIMAL(12, 2)) AS pct, CAST(SUM(W2.pct) AS DECIMAL(12, 2)) AS running_pct FROM Waits AS W1 INNER JOIN Waits AS W2 ON W2.rn <= W1.rn GROUP BY W1.rn, W1.wait_type, W1.wait_time_s, W1.pct HAVING SUM(W2.pct) - W1.pct < 90 -- percentage threshold ORDER BY W1.rn; */ /* create table #waits (type varchar(128), req bigint, waittime bigint, signal bigint) truncate table #waits insert into #waits exec(''dbcc sqlperf(waitstats)'') --insert into _LakeSide_DbTools_WaitsLogger_WaitsLog (DT,CPU,Locks,Reads,Writes,Network,PhReads,PhWrites,LgReads) select getdate() AS DT, CAST(@@CPU_BUSY * CAST(@@TIMETICKS AS FLOAT) / 1000 AS BIGINT) as CPU, -- in milliseconds sum(convert(bigint, case when type like ''LCK%'' then waittime else 0 end)) as Locks, sum(convert(bigint, case when type like ''LATCH%'' or type like ''PAGELATCH%'' or type like ''PAGEIOLATCH%'' then waittime else 0 end)) as Reads, sum(convert(bigint, case when type like ''%IO_COMPLETION%'' or type=''WRITELOG'' then waittime else 0 end)) as Writes, sum(convert(bigint, case when type in (''NETWORKIO'',''OLEDB'') then waittime else 0 end)) as Network, @@TOTAL_READ AS PhReads, @@TOTAL_WRITE AS PhWrites, ISNULL((select cntr_value from master.dbo.sysperfinfo where counter_name=''Page lookups/sec''), 0) AS LgReads -- select * from #waits truncate table #waits insert into #waits exec(''dbcc sqlperf(waitstats)'') --insert into _LakeSide_DbTools_WaitsLogger_WaitsLog (DT,CPU,Locks,Reads,Writes,Network,PhReads,PhWrites,LgReads) select getdate() AS DT, CAST(@@CPU_BUSY * CAST(@@TIMETICKS AS FLOAT) / 1000 AS BIGINT) as CPU, -- in milliseconds sum(convert(bigint, case when type like ''LCK%'' then waittime else 0 end)) as Locks, sum(convert(bigint, case when type like ''LATCH%'' or type like ''PAGELATCH%'' or type like ''PAGEIOLATCH%'' then waittime else 0 end)) as Reads, sum(convert(bigint, case when type like ''%IO_COMPLETION%'' or type=''WRITELOG'' then waittime else 0 end)) as Writes, sum(convert(bigint, case when type in (''NETWORKIO'',''OLEDB'') then waittime else 0 end)) as Network, @@TOTAL_READ AS PhReads, @@TOTAL_WRITE AS PhWrites, ISNULL((select cntr_value from master.dbo.sysperfinfo where counter_name=''Page lookups/sec''), 0) AS LgReads -- select * from #waits */ -- collect processord usage of last 4 hours -- declare @ts_now bigint exec sp_executesql N'' select @ts_now = cpu_ticks / convert(float, cpu_ticks_in_ms) from sys.dm_os_sys_info '',N''@ts_now bigint out'',@ts_now=@ts_now out select record_id, dateadd(ms, -1 * ( @ts_now - [timestamp] ), getdate()) as eventtime, sqlprocessutilization, systemidle, 100 - systemidle - sqlprocessutilization as otherprocessutilization into #usage from ( select -- !!!! values of record.value are case sensitive record.value(''(./Record/@id)[1]'', ''int'') AS record_id, record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]'',''int'') AS systemidle, record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]'', ''int'') AS sqlprocessutilization, timestamp from ( select timestamp, convert(xml, record) as record from sys.dm_os_ring_buffers where ring_buffer_type = N''ring_buffer_scheduler_monitor'' and record like ''%%'') as x ) as y order by record_id desc select @from=min(eventtime), @to=max(eventtime), @sql=avg(sqlprocessutilization), @idle=avg(systemidle), @other=avg(otherprocessutilization) from #usage if @sql is null goto err_ver exec sp__printf '' Avg of last 4 hours of cpu usage: from:%s to:%s mssql : %d idle : %d other : %d'', @from,@to,@sql,@idle,@other select @n=30 while (@n>0) begin exec sp__printf ''Waiting for MSSQL exceed 80% of CPU usage'' select @sql=0 while (@sql<81) select top 1 @sql=sqlprocessutilization from ( select -- !!!! values of record.value are case sensitive record.value(''(./Record/@id)[1]'', ''int'') AS record_id, record.value(''(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]'', ''int'') AS sqlprocessutilization from ( select timestamp, convert(xml, record) as record from sys.dm_os_ring_buffers where ring_buffer_type = N''ring_buffer_scheduler_monitor'' and record like ''%%'') as x ) as y order by record_id desc -- SELECT * FROM sys.dm_os_threads WHERE started_by_sqlservr = 0; -- show thread usage select p.spid,t.kernel_time,t.usermode_time,getdate() d,sql_handle into #a from sys.dm_os_threads t join master..sysprocesses p on p.kpid=os_thread_id where p.spid>50 waitfor delay ''00:00:001'' select p.spid,t.kernel_time,t.usermode_time,getdate() d,sql_handle into #b from sys.dm_os_threads t join master..sysprocesses p on p.kpid=os_thread_id where p.spid>50 select getdate() dt, a.spid, b.kernel_time-a.kernel_time+b.usermode_time-a.usermode_time times, datediff(ms,a.d,b.d) ms, db_name(t.dbid) db, object_name(t.objectid) /*,t.dbid)*/ obj, t.text into #c from #a a join #b b on a.spid=b.spid and a.sql_handle=b.sql_handle cross apply sys.dm_exec_sql_text (a.sql_handle) t where b.kernel_time-a.kernel_time+b.usermode_time-a.usermode_time>1000 if @@rowcount>0 begin select * from #c order by times desc select @n=@n-1 end drop table #a drop table #b drop table #c -- see also sys.dm_os_workers end -- infinite loop goto ret -- =================================================================== errors == err_ver: exec @ret=sp__err ''this version of MSSQL do not support completelly '',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope [write here a short desc] Parameters [param] [desc] Examples [exam ple] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__perf_monitor' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf_monitor: -- =============================================================== sp__perf_shot select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf_shot',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130228 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf_shot') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf_shot') with nowait goto skip_sp__perf_shot end if @ver>130228 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf_shot') with nowait goto skip_sp__perf_shot end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf_shot') with nowait if exists( select top 1 null from sys.objects where name='sp__perf_shot' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf_shot] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:performance, snapshot, r:130228\s.zaglio: take a snapshot of system for performance evaluation t:sp__perf_shot run */ CREATE proc sp__perf_shot @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- show if phisical disk is involved in I/O bottleneck(?) -- heavy i/o select db_name(t1.database_id) db, file_name(t1.file_id) fname, t1.io_stall, t2.io_pending_ms_ticks, object_name(sql.objectid) obj, case when sql_handle is null then '' '' else ( substring(sql.text,(er.statement_start_offset+2)/2,(case when er.statement_end_offset = -1 then len(convert(nvarchar(max),sql.text))*2 else er.statement_end_offset end - er.statement_start_offset) /2 ) ) end as stm, text as sql from sys.dm_io_virtual_file_stats(NULL, NULL)t1 join sys.dm_io_pending_io_requests as t2 on t1.file_handle = t2.io_handle left join sys.dm_os_schedulers os on t2.scheduler_address=os.scheduler_address left join sys.dm_os_workers ow on os.active_worker_address=ow.worker_address left join sys.dm_exec_requests er on er.task_address=ow.task_address cross apply sys.dm_exec_sql_text(er.sql_handle) as sql where io_pending_ms_ticks>20 -- batch that generate most i/o in general select top 10 (total_logical_reads/execution_count) as avg_logical_reads, (total_logical_writes/execution_count) as avg_logical_writes, (total_physical_reads/execution_count) as avg_phys_reads, Execution_count, statement_start_offset as stmt_start_offset, --sql_handle, --plan_handle, st.text, object_name(st.objectid) obj, case when sql_handle is null then '' '' else ( substring(st.text,(qs.statement_start_offset+2)/2,(case when qs.statement_end_offset = -1 then len(convert(nvarchar(max),st.text))*2 else qs.statement_end_offset end - qs.statement_start_offset) /2 ) ) end as stm from sys.dm_exec_query_stats qs cross apply sys.dm_exec_sql_text( sql_handle) st order by (total_logical_reads + total_logical_writes) Desc -- in general -- batch that generate most i/o in single execution select top 10 (total_logical_reads/execution_count) as avg_logical_reads, (total_logical_writes/execution_count) as avg_logical_writes, (total_physical_reads/execution_count) as avg_phys_reads, Execution_count, -- statement_start_offset as stmt_start_offset, --sql_handle, --plan_handle, object_name(st.objectid) obj, case when sql_handle is null then '' '' else ( substring(st.text,(qs.statement_start_offset+2)/2,(case when qs.statement_end_offset = -1 then len(convert(nvarchar(max),st.text))*2 else qs.statement_end_offset end - qs.statement_start_offset) /2 ) ) end as stm, st.text from sys.dm_exec_query_stats qs cross apply sys.dm_exec_sql_text( sql_handle) st order by (total_logical_reads + total_logical_writes)/execution_count -- the following query shows the top 50 sql statements with high average cpu consumption. select top 10 total_worker_time/execution_count as [avg cpu time], object_name(objectid) obj, substring(text,statement_start_offset/2,(case when statement_end_offset = -1 then len(convert(nvarchar(max), text)) * 2 else statement_end_offset end -statement_start_offset)/2) as sql from sys.dm_exec_query_stats cross apply sys.dm_exec_sql_text(sql_handle) order by [avg cpu time] desc -- How to determine whether any active requests are running in parallel for a given session Select object_name(sql.objectid) obj, substring(text,statement_start_offset/2,(case when statement_end_offset = -1 then len(convert(nvarchar(max), text)) * 2 else statement_end_offset end -statement_start_offset)/2) as sql, r.session_id, r.request_id, max(isnull(exec_context_id, 0)) as number_of_workers, r.sql_handle,r.statement_start_offset,r.statement_end_offset, r.plan_handle from sys.dm_exec_requests r join sys.dm_os_tasks t on r.session_id = t.session_id join sys.dm_exec_sessions s on r.session_id = s.session_id cross apply sys.dm_exec_sql_text(sql_handle) as sql where s.is_user_process = 0x1 group by r.session_id, r.request_id, r.sql_handle, r.plan_handle, r.statement_start_offset, r.statement_end_offset,sql.objectid,sql.text having max(isnull(exec_context_id, 0)) > 0 -- 6. How to find the total number of worker threads in the runnable state (Waiting for CPU)? select count(*) as workers_waiting_for_cpu, s.scheduler_id from sys.dm_os_workers as o inner join sys.dm_os_schedulers as s on o.scheduler_address = s.scheduler_address and s.scheduler_id < 255 where o.state = ''runnable'' group by s.scheduler_id -- 7. query gives you the top 25 stored procedures that have been recompiled. The plan_generation_num indicates the number of times the query has recompiled. select top 25 db_name(dbid) db, object_name(sql_text.objectid) obj, sql_text.text, -- sql_handle, sum(plan_generation_num) as plan_generation_num, sum(execution_count) execution_count from sys.dm_exec_query_stats a cross apply sys.dm_exec_sql_text(sql_handle) as sql_text where plan_generation_num > 1 group by dbid,sql_text.objectid,sql_text.text order by plan_generation_num desc -- 8. How to find the all sessions on SQL Server 2005? select s.session_id , s.login_time , s.host_name, s.program_name, s.cpu_time / 1000.0 as cpu_time, s.memory_usage*8 as memory_usage , s.login_name, s.nt_domain, s.nt_user_name, c.connect_time, c.num_reads, c.num_writes, c.client_net_address , c.client_tcp_port, c.session_id , case when r.sql_handle is not null then (select top 1 SUBSTRING(t2.text, (r.statement_start_offset + 2) / 2, ( (case when r.statement_end_offset = -1 then ((len(convert(nvarchar(MAX),t2.text))) * 2) else r.statement_end_offset end) - r.statement_start_offset) / 2) from sys.dm_exec_sql_text(r.sql_handle) t2 ) else '''' end as sql_statement from sys.dm_exec_sessions s left outer join sys.dm_exec_connections c on ( s.session_id = c.session_id ) left outer join sys.dm_exec_requests r on ( r.session_id = c.session_id and r.connection_id = c.connection_id ) where s.is_user_process = 1 -- How to find the TEMP DB space availability? select sum (user_object_reserved_page_count)*8 as user_objects_kb, sum (internal_object_reserved_page_count)*8 as internal_objects_kb, sum (version_store_reserved_page_count)*8 as version_store_kb, sum (unallocated_extent_page_count)*8 as freespace_kb -- select * from sys.dm_db_file_space_usage where database_id = 2 -- 12. How to list the Queries by total IO? select top 10 rank() over (order by total_logical_reads+total_logical_writes desc,sql_handle,statement_start_offset ) as row_no , creation_time, last_execution_time, (total_worker_time+0.0)/1000 as total_worker_time , (total_worker_time+0.0)/(execution_count*1000) as [AvgCPUTime] , total_logical_reads as [LogicalReads], total_logical_writes as [LogicalWrites] , execution_count, total_logical_reads+total_logical_writes as [AggIO] , (total_logical_reads+total_logical_writes)/(execution_count+0.0) as [AvgIO] , case when sql_handle IS NULL then '' '' else ( substring(st.text,(qs.statement_start_offset+2)/2,(case when qs.statement_end_offset = -1 then len(convert(nvarchar(MAX),st.text))*2 else qs.statement_end_offset end - qs.statement_start_offset) /2 ) ) end as query_text , db_name(st.dbid) as database_name , st.objectid as object_id , object_name(st.objectid) obj from sys.dm_exec_query_stats qs cross apply sys.dm_exec_sql_text(sql_handle) st where total_logical_reads+total_logical_writes > 0 order by [AggIO] desc -- 11. How to list the queries by Total CPU Time? select rank() over(order by total_worker_time desc,sql_handle,statement_start_offset) as row_no , creation_time, last_execution_time, (total_worker_time+0.0)/1000 as total_worker_time , (total_worker_time+0.0)/(execution_count*1000) as [AvgCPUTime] , total_logical_reads as [LogicalReads], total_logical_writes as [logicalWrites] , execution_count, total_logical_reads+total_logical_writes as [AggIO] , (total_logical_reads+total_logical_writes)/(execution_count + 0.0) as [AvgIO] , case when sql_handle IS NULL then '' '' else ( substring(st.text,(qs.statement_start_offset+2)/2,(case when qs.statement_end_offset = -1 then len(convert(nvarchar(MAX),st.text))*2 else qs.statement_end_offset end - qs.statement_start_offset) /2 ) ) end as query_text , db_name(st.dbid) as database_name , st.objectid as object_id , object_name(st.objectid) obj from sys.dm_exec_query_stats qs cross apply sys.dm_exec_sql_text(sql_handle) st where total_worker_time > 0 order by total_worker_time desc -- show wait types select top 10 * from sys.dm_os_wait_stats --where wait_type not in (''CLR_SEMAPHORE'',''LAZYWRITER_SLEEP'',''RESOURCE_QUEUE'',''SLEEP_TASK'',''SLEEP_SYSTEMTASK'',''WAITFOR'') order by wait_time_ms desc begin try declare @tab_tran_locks as table( l_resource_type nvarchar(60) collate database_default , l_resource_subtype nvarchar(60) collate database_default , l_resource_associated_entity_id bigint , l_blocking_request_spid int, l_blocked_request_spid int, l_blocking_request_mode nvarchar(60) collate database_default , l_blocked_request_mode nvarchar(60) collate database_default, l_blocking_tran_id bigint, l_blocked_tran_id bigint ); declare @tab_blocked_tran as table ( tran_id bigint , no_blocked bigint ); declare @temp_tab table( blocking_status int, no_blocked int, l_resource_type nvarchar(60) collate database_default , l_resource_subtype nvarchar(60) collate database_default , l_resource_associated_entity_id bigint , l_blocking_request_spid int, l_blocked_request_spid int, l_blocking_request_mode nvarchar(60) collate database_default , l_blocked_request_mode nvarchar(60) collate database_default , l_blocking_tran_id int, l_blocked_tran_id int , local1 int, local2 int, b_tran_id bigint, w_tran_id bigint, b_name nvarchar(128) collate database_default , w_name nvarchar(128) collate database_default , b_tran_begin_time datetime, w_tran_begin_time datetime , b_state nvarchar(60) collate database_default , w_state nvarchar(60) collate database_default , b_trans_type nvarchar(60) collate database_default , w_trans_type nvarchar(60) collate database_default , b_text nvarchar(max) collate database_default , w_text nvarchar(max) collate database_default , db_span_count1 int, db_span_count2 int ); insert into @tab_tran_locks select a.resource_type, a.resource_subtype, a.resource_associated_entity_id, a.request_session_id as blocking , b.request_session_id as blocked, a.request_mode, b.request_mode , a.request_owner_id , b.request_owner_id from sys.dm_tran_locks a join sys.dm_tran_locks b on (a.resource_type = b.resource_type and a.resource_subtype = b.resource_subtype and a.resource_associated_entity_id = b.resource_associated_entity_id and a.resource_description = b.resource_description) where a.request_status = ''GRANT'' and (b.request_status = ''WAIT'' or b.request_status = ''CONVERT'') and a.request_owner_type = ''TRANSACTION'' and b.request_owner_type = ''TRANSACTION'' insert into @tab_blocked_tran select ttl.l_blocking_tran_id, count(distinct ttl.l_blocked_tran_id) from @tab_tran_locks ttl group by ttl.l_blocking_tran_id order by count( distinct ttl.l_blocked_tran_id) desc insert into @temp_tab select 0 as blocking_status, tbt.no_blocked, ttl.*, st1.is_local as local1, st2.is_local as local2 , st1.transaction_id as b_tran_id, st2.transaction_id as w_tran_id, at1.name as b_name,at2.name as w_name , at1.transaction_begin_time as b_tran_begin_time, at2.transaction_begin_time as w_tran_begin_time , case when at1.transaction_type <> 4 then case at1.transaction_state when 0 then ''Invalid'' when 1 then ''Initialized'' when 2 then ''Active'' when 3 then ''Ended'' when 4 then ''Commit Started'' when 5 then ''Prepared'' when 6 then ''Committed'' when 7 then ''Rolling Back'' when 8 then ''Rolled Back'' end else case at1.dtc_state when 1 then ''Active'' when 2 then ''Prepared'' when 3 then ''Committed'' when 4 then ''Aborted'' when 5 then ''Recovered'' end end b_state , case when at2.transaction_type <> 4 then case at2.transaction_state when 0 then ''Invalid'' when 1 then ''Initialized'' when 2 then ''Active'' when 3 then ''Ended'' when 4 then ''Commit Started'' when 5 then ''Prepared'' when 6 then ''Committed'' when 7 then ''Rolling Back'' when 8 then ''Rolled Back'' end else case at2.dtc_state when 1 then ''Active'' when 2 then ''Prepared'' when 3 then ''Committed'' when 4 then ''Aborted'' when 5 then ''Recovered'' end end w_state, at1.transaction_type as b_trans_type , at2.transaction_type as w_trans_type, case when r1.sql_handle IS NULL then ''--'' else ( select top 1 substring(text,(r1.statement_start_offset+2)/2, (case when r1.statement_end_offset = -1 then len(convert(nvarchar(MAX),text))*2 else r1.statement_end_offset end - r1.statement_start_offset) /2 ) from sys.dm_exec_sql_text(r1.sql_handle)) end as b_text, case when r2.sql_handle IS NULL then ''--'' else ( select top 1 substring(text,(r2.statement_start_offset+2)/2, (case when r2.statement_end_offset = -1 then len(convert(nvarchar(MAX),text))*2 else r2.statement_end_offset end - r2.statement_start_offset) /2 ) from sys.dm_exec_sql_text(r2.sql_handle)) end as w_text , ( Select count(distinct database_id) from sys.dm_tran_database_transactions where transaction_id = st1.transaction_id ) as db_span_count1, ( Select count(distinct database_id) from sys.dm_tran_database_transactions where transaction_id = st2.transaction_id ) as db_span_count2 from @tab_tran_locks ttl inner join sys.dm_tran_active_transactions at1 on(at1.transaction_id = ttl.l_blocking_tran_id) inner join @tab_blocked_tran tbt on(tbt.tran_id = at1.transaction_id) inner join sys.dm_tran_session_transactions st1 on(at1.transaction_id = st1.transaction_id) left outer join sys.dm_exec_requests r1 on(at1.transaction_id = r1.transaction_id ) inner join sys.dm_tran_active_transactions at2 on(at2.transaction_id = ttl.l_blocked_tran_id) inner join sys.dm_tran_session_transactions st2 on(at2.transaction_id = st2.transaction_id) left outer join sys.dm_exec_requests r2 on(at2.transaction_id = r2.transaction_id ) where st1.is_user_transaction = 1 and st2.is_user_transaction = 1 order by tbt.no_blocked desc; with Blocking( blocking_status, no_blocked, total_blocked, l_resource_type, l_resource_subtype , l_resource_associated_entity_id, l_blocking_request_spid, l_blocked_request_spid, l_blocking_request_mode , l_blocked_request_mode, local1, local2, b_tran_id, w_tran_id, b_name, w_name, b_tran_begin_time , w_tran_begin_time, b_state, w_state, b_trans_type, w_trans_type, b_text, w_text, db_span_count1 , db_span_count2, lvl) as( select blocking_status , no_blocked , no_blocked , l_resource_type , l_resource_subtype , l_resource_associated_entity_id , l_blocking_request_spid , l_blocked_request_spid , l_blocking_request_mode , l_blocked_request_mode , local1 , local2 , b_tran_id , w_tran_id , b_name , w_name , b_tran_begin_time , w_tran_begin_time , b_state , w_state , b_trans_type , w_trans_type , b_text , w_text , db_span_count1 , db_span_count2 , 0 from @temp_tab union all select E.blocking_status , M.no_blocked , convert(int,E.no_blocked + total_blocked) , E.l_resource_type , E.l_resource_subtype , E.l_resource_associated_entity_id , M.l_blocking_request_spid , E.l_blocked_request_spid , M.l_blocking_request_mode , E.l_blocked_request_mode , M.local1 , E.local2 , M.b_tran_id , E.w_tran_id , M.b_name , E.w_name , M.b_tran_begin_time , E.w_tran_begin_time , M.b_state , E.w_state , M.b_trans_type , E.w_trans_type , M.b_text , E.w_text , M.db_span_count1 , E.db_span_count2 , M.lvl+1 from @temp_tab as E join Blocking as M on E.b_tran_id = M.w_tran_id ) select * from Blocking order by no_blocked desc,b_tran_id,w_tran_id ; end try begin catch select ERROR_SEVERITY() as blocking_status , ERROR_STATE() as no_blocked , ERROR_MESSAGE() as total_blocked , 1 as l_resource_type,1 as l_resource_subtype,1 as l_resource_associated_entity_id,1 as l_blocking_request_spid,1 as l_blocked_request_spid,1 as l_blocking_request_mode,1 as l_blocked_request_mode,1 as local1,1 as local2,1 as b_tran_id,1 as w_tran_id,1 as b_name,1 as w_name,1 as b_tran_begin_time,1 as w_tran_begin_time,1 as b_state,1 as w_state,1 as b_trans_type,1 as w_trans_type,1 as b_text,1 as w_text,1 as db_span_count1,1 as db_span_count2,1 as lvl end catch goto dispose -- shows some operators that may be CPU intensive, such as ‘%Hash Match%’, ‘%Sort%’ to look for suspects. select object_name(objectid) obj,* from sys.dm_exec_cached_plans cross apply sys.dm_exec_query_plan(plan_handle) where cast(query_plan as nvarchar(max)) like ''%Sort%'' or cast(query_plan as nvarchar(max)) like ''%Hash Match%'' -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope take a snapshot of system to do some evaluation about performance Parameters @opt options run execute Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__perf_shot' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf_shot: -- ============================================================= sp__perf_worsts select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__perf_worsts',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120609 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__perf_worsts') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__perf_worsts') with nowait goto skip_sp__perf_worsts end if @ver>120609 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__perf_worsts') with nowait goto skip_sp__perf_worsts end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__perf_worsts') with nowait if exists( select top 1 null from sys.objects where name='sp__perf_worsts' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__perf_worsts] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,perf v:120609\s.zaglio: refine r:120113\s.zaglio: show worst queryes c: orinally from http://www.databasejournal.com/features/mssql/article.php/3802936/ Finding-the-Worst-Performing-T-SQL-Statements-on-an-Instance.htm written by: gregory a. larsen copyright © 2008 gregory a. larsen. all rights reserved. */ CREATE proc sp__perf_worsts @opt sysname = null, @dbg int = null as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @opt=''||'' goto help -- ============================================================== declaration == declare @dbname varchar(128),@count int,@orderby varchar(4) -- =========================================================== initialization == select @dbname = '''', @count = 999999999, @orderby = ''aio'' -- ======================================================== second params chk == -- ===================================================================== body == exec sp__printf ''-- collecting info...'' /* check for valid @orderby parameter if ((select case when @orderby in (''acpu'',''tcpu'',''ae'',''te'',''ec'',''aio'',''tio'',''alr'',''tlr'',''alw'',''tlw'',''apr'',''tpr'') then 1 else 0 end) = 0) begin -- abort if invalid @orderby parameter entered raiserror(''@orderby parameter not apcu, tcpu, ae, te, ec, aio, tio, alr, tlr, alw, tlw, apr or tpr'',11,1) return end */ select top (@count) coalesce(db_name(st.dbid), db_name(cast(pa.value as int))+''*'', ''resource'') as [database name] -- find the offset of the actual statement being executed ,substring(text, case when statement_start_offset = 0 or statement_start_offset is null then 1 else statement_start_offset/2 + 1 end, case when statement_end_offset = 0 or statement_end_offset = -1 or statement_end_offset is null then len(text) else statement_end_offset/2 end - case when statement_start_offset = 0 or statement_start_offset is null then 1 else statement_start_offset/2 end + 1 ) as [statement] ,object_schema_name(st.objectid,dbid) [schema name] ,object_name(st.objectid,dbid) [object name] ,objtype [cached plan objtype] ,execution_count [execution count] ,(total_logical_reads + total_logical_writes + total_physical_reads )/execution_count [average ios] ,total_logical_reads + total_logical_writes + total_physical_reads [total ios] ,total_logical_reads/execution_count [avg logical reads] ,total_logical_reads [total logical reads] ,total_logical_writes/execution_count [avg logical writes] ,total_logical_writes [total logical writes] ,total_physical_reads/execution_count [avg physical reads] ,total_physical_reads [total physical reads] ,total_worker_time / execution_count [avg cpu] ,total_worker_time [total cpu] ,total_elapsed_time / execution_count [avg elapsed time] ,total_elapsed_time [total elasped time] ,last_execution_time [last execution time] into #perf_worsts from sys.dm_exec_query_stats qs join sys.dm_exec_cached_plans cp on qs.plan_handle = cp.plan_handle cross apply sys.dm_exec_sql_text(qs.plan_handle) st outer apply sys.dm_exec_plan_attributes(qs.plan_handle) pa where attribute = ''dbid'' and case when @dbname = '''' then '''' else coalesce(db_name(st.dbid), db_name(cast(pa.value as int)) + ''*'', ''resource'') end in (rtrim(@dbname),rtrim(@dbname) + ''*'') select * from #perf_worsts order by case when @orderby = ''acpu'' then [total cpu] / [execution count] when @orderby = ''tcpu'' then [total cpu] when @orderby = ''ae'' then [total elasped time] / [execution count] when @orderby = ''te'' then [total elasped time] when @orderby = ''ec'' then [execution count] when @orderby = ''aio'' then ([total logical reads] + [total logical writes] + [total physical reads]) / [execution count] when @orderby = ''tio'' then [total logical reads] + [total logical writes] + [total physical reads] when @orderby = ''alr'' then [total logical reads] / [execution count] when @orderby = ''tlr'' then [total logical reads] when @orderby = ''alw'' then [total logical writes] / [execution count] when @orderby = ''tlw'' then [total logical writes] when @orderby = ''apr'' then [total physical reads] / [execution count] when @orderby = ''tpr'' then [total physical reads] end desc goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope this stored procedure displays the top worst performing queries based on cpu, execution count, i/o and elapsed_time as identified using dmv information. this can be display the worst performing queries from an instance, or database perspective. the number of records shown, the database, and the sort order are identified by passing pararmeters. Parameters @opt options run run collection of performance info @dbg not used Notes "acpu" represents average cpu usage "tcpu" represents total cpu usage "ae" represents average elapsed time "te" represents total elapsed time "ec" represents execution count "aio" represents average ios "tio" represents total ios "alr" represents average logical reads "tlr" represents total logical reads "alw" represents average logical writes "tlw" represents total logical writes "apr" represents average physical reads "tpr" represents total physical read Examples exec sp__perf_worsts @code=''''sp__perf_worsts'''' '' /* top 6 statements in the adventureworks database base on average cpu usage: exec usp_worst_tsql @dbname=''adventureworks'',@count=6,@orderby=''acpu''; top 100 statements order by average io exec usp_worst_tsql @count=100,@orderby=''alr''; show top all statements by average io exec usp_worst_tsql; */ select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__perf_worsts' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__perf_worsts: -- ==================================================================== sp__pkey select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__pkey',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100523 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__pkey') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__pkey') with nowait goto skip_sp__pkey end if @ver>100523 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__pkey') with nowait goto skip_sp__pkey end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__pkey') with nowait if exists( select top 1 null from sys.objects where name='sp__pkey' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__pkey] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100523\s.zaglio: a bug near counts and added excludes v:100321\s.zaglio: return pkey''s fields or finds possibles t:sp__pkey ''MATMAS_MARAM'',@dbg=1 t: sp__pkey ''MATMAS04_MARA_MTXH_MTXL'' select * from MATMAS04_MARA_MTXH_MTXL sios_select ''*'',''MTXH'' */ CREATE proc sp__pkey @tbl sysname=null, @pk nvarchar(512)=null, @excludes sysname=null, @dbg bit=0 as begin declare @proc sysname,@ret int select @proc=''sp__pkey'',@ret=0 if @tbl is null goto help declare @flds nvarchar(4000),@i int,@n int,@nr bigint,@r bigint, @sql nvarchar(4000),@fld sysname,@pks int select @flds=dbo.fn__flds_of(@tbl,'','',@excludes) if @dbg=1 exec sp__printf ''%s'',@flds select @i=1,@n=dbo.fn__str_count(@flds,'','') exec sp__count @tbl,@nr out select @pks=0 while (@i<=@n) begin select @fld=dbo.fn__str_at(@flds,'','',@i) select @sql=''select @r=count(*) from (select distinct [''+@fld+''] from [''+@tbl+'']) a'' if @dbg=1 select @sql=@sql+'' print @r'' select @r=null if @dbg=1 exec sp__printf @sql exec sp_executesql @sql,N''@r bigint out'',@r=@r out if @r=@nr begin if @pk is null select @pk=@fld exec sp__printf ''%s possible pk:%s'',@tbl,@fld select @pks=@pks+1 end select @i=@i+1 end -- TODO:if @pks=0 ... search for combination goto ret help: exec sp__usage @proc ret: return @ret end -- sp__pkey' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__pkey: -- ====================================================== sp__plan_calendar_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__plan_calendar_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121118 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__plan_calendar_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__plan_calendar_test') with nowait goto skip_sp__plan_calendar_test end if @ver>121118 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__plan_calendar_test') with nowait goto skip_sp__plan_calendar_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__plan_calendar_test') with nowait if exists( select top 1 null from sys.objects where name='sp__plan_calendar_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__plan_calendar_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,plan k:plan,calendar,test r:121118\s.zaglio: test plan calendar functions */ CREATE proc sp__plan_calendar_test @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare @days nvarchar(24), @i int,@dt datetime, @end_declare bit -- =========================================================== initialization == select @i=1, @days='''', @end_declare=1 -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == select cast(dbo.fn__plan_calendar(''2012-01-01'','''') as varbinary(48)) as [12-01-01], cast(dbo.fn__plan_calendar(''2012-31-01'','''') as varbinary(48)) as [12-31-01], cast(dbo.fn__plan_calendar(''2012-01-02'','''') as varbinary(48)) as [12-01-02], dt from dbo.fn__plan_dates(2012,dbo.fn__plan_calendar(''2012-01-01'','''')) while @i<13 begin select -- 1st day of month @dt=''2012-01-''+right(''00''+cast(@i as varchar(2)),2), @days=dbo.fn__plan_calendar(@dt,@days) -- last day of month exec sp__printf ''dt=%s'',@dt select @dt=case @i when 12 then ''2012-31-12'' else convert(datetime,''2012-01-''+right(''00''+cast(@i+1 as varchar(2)),2))-1 end, @days=dbo.fn__plan_calendar(@dt,@days), @i=@i+1 exec sp__printf ''dt=%s'',@dt end select cast(@days as varbinary(48)) days select * from dbo.fn__plan_dates(2012,@days) -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''write here msg'' goto err err_me2: select @e_msg=''write this %s'',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test plan calendar functions Parameters [param] [desc] Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__plan_calendar_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__plan_calendar_test: -- ============================================================= sp__print_table select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__print_table',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__print_table') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__print_table') with nowait goto skip_sp__print_table end if @ver>100919 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__print_table') with nowait goto skip_sp__print_table end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__print_table') with nowait if exists( select top 1 null from sys.objects where name='sp__print_table' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__print_table] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919\s.zaglio: solved problem of print '''' v:100501\s.zaglio: added @reverse v:091229\s.zaglio: added @prefix v:091128\s.zaglio: a small optimization v:091127\s.zaglio: added @format to use s__printf instead of print v:091018\s.zaglio: will replace part or all sp__select. Used by sp__script,sp__copy t: create table #src (lno int identity(10,10),line nvarchar(4000)) insert #src(line) select ''hello'' insert #src(line) select null insert #src(line) select ''world'' exec sp__print_table ''#src'' -- ,@dbg=1 exec sp__print_table ''#src'',@prefix=''tst:'' exec sp__print_table ''(select lno,line from #src)'',@dbg=1 drop table #src */ CREATE proc [dbo].[sp__print_table] @tbl sysname =null, @autosize bit=0, @sizes sysname=null, -- 20|10|5 chars @title sysname=null, @format bit=0, @prefix sysname=null, @reverse bit=0, @dbg bit=0 as begin set nocount on declare @proc sysname, @print sysname, @sql nvarchar(4000),@msg nvarchar(4000) select @proc =''sp__print_table'' if @tbl is null goto help if @prefix is null select @print=case @format when 0 then ''if len(@line)=0 print char(13)+char(10) else print @line '' else ''exec sp__printf ''''%s'''',@line '' end else begin select @prefix=replace(@prefix,'''''''','''''''''''') select @print=case @format when 0 then ''if len(@line)=0 print char(13)+char(10) else print ''''''+@prefix+''''''+@line '' else ''exec sp__printf ''''''+@prefix+''%s'''',@line '' end end select @sql =''declare @line nvarchar(4000);'' +''declare lines cursor local for select coalesce(line,'''''''') as line from ''+@tbl+'' tbl order by lno '' +case when @reverse=1 then ''desc;'' else '';'' end +''open lines;'' +''while (1=1) '' +''begin '' +''fetch next from lines into @line '' +''if @@error != 0 or @@fetch_status != 0 break '' +@print +''end;'' +''close lines deallocate lines;'' if not @title is null exec sp__printf @title if @dbg=1 exec sp__printf @sql exec(@sql) goto ret err_todo: help: select @msg=''NB. actually work only for tables (lno int,line nvarchar(max))'' exec sp__usage @proc,@msg ret: end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__print_table: -- ================================================================== sp__printf select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__printf',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130606 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__printf') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__printf') with nowait goto skip_sp__printf end if @ver>130606 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__printf') with nowait goto skip_sp__printf end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__printf') with nowait if exists( select top 1 null from sys.objects where name='sp__printf' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__printf] begin try exec dbo.sp_executesql @statement = N'/* keep for MS compatibility l:see LICENSE file g:utility v:130606\s.zaglio: moved @force and @format_only into @opt v:130605\s.zaglio: added output of the result to @format,corrected help v:130424\s.zaglio: a small bug near leng>0 and resumed +1 of bug 130416 v:130416\s.zaglio: a bug when called from printsql near crlf v:121010\s.zaglio: added {1}... markers v:110831\s.zaglio: a bug or misunderstanding near @format_only v:110705\s.zaglio: a bug near @tmp v:110607\s.zaglio: a bug near last \n v:110526\s.zaglio: a bug near last \n%s v:110518\s.zaglio: a bug near optimization v:110517\s.zaglio: a bug when more %s/d than supported v:110510\s.zaglio: escaped % in raiserror to exclude error 2787:Invalid format spec. v:110421\s.zaglio: used nvarchar(max) instead of ntext v:110314\s.zaglio: added split into 200 char''s lines v:110312\s.zaglio: a semiremake of sp__printf to allow >4000 chars (mssql2k compatible) t:sp__printf_test */ CREATE proc [dbo].[sp__printf] @format nvarchar(max)=null out, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @p5 sql_variant=null, @p6 sql_variant=null, @p7 sql_variant=null, @p8 sql_variant=null, @p9 sql_variant=null, @p0 sql_variant=null, @opt sysname=null, @dbg bit=null --,@err sysname=null 100106\s.zaglio: not so useful as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if not @opt is null select @opt=dbo.fn__Str_quote(@opt,''|'') -- ============================================================== declaration == declare @icrlf bit,@sep nvarchar(2), @p int,@j int,@i1 int, @crlf nvarchar(2),@macro nvarchar(4000), @cr nchar(1),@lf nchar(1), @tmp nvarchar(4000), @nm bit, -- new markers @p1s nvarchar(4000), @p2s nvarchar(4000), @p3s nvarchar(4000), @p4s nvarchar(4000), @p5s nvarchar(4000), @p6s nvarchar(4000), @p7s nvarchar(4000), @p8s nvarchar(4000), @p9s nvarchar(4000), @p0s nvarchar(4000) declare @out table(lno int identity primary key,line nvarchar(4000)) select @icrlf=0 -- not include crlf into splittings declare @lines table (pos int primary key,leng int) declare @i int,@n int,@k int,@st sysname, @bs int, -- buffer size or the width of output @format_only bit, @force bit, @test bit select @bs=200,@dbg=isnull(@dbg,0),@crlf=crlf,@cr=cr,@lf=lf, @force=1-isnull(charindex(''|print|'',@opt),0), @format_only=isnull(charindex(''|fo|'',@opt),0), @test=isnull(charindex(''|test|'',@opt),0) from dbo.fn__sym() if @format is null goto help -- optimization for empty strings if @format='''' begin if @test=0 begin if @force=1 raiserror(@crlf,10,1) with nowait else print '''' end insert @out select '''' goto dispose end if charindex(''{1}'',@format)>0 begin select @nm=1 select @p1s=isnull(convert(nvarchar(4000),@p1,126),''(null)'') select @p2s=isnull(convert(nvarchar(4000),@p2,126),''(null)'') select @p3s=isnull(convert(nvarchar(4000),@p3,126),''(null)'') select @p4s=isnull(convert(nvarchar(4000),@p4,126),''(null)'') select @p5s=isnull(convert(nvarchar(4000),@p5,126),''(null)'') select @p6s=isnull(convert(nvarchar(4000),@p6,126),''(null)'') select @p7s=isnull(convert(nvarchar(4000),@p7,126),''(null)'') select @p8s=isnull(convert(nvarchar(4000),@p8,126),''(null)'') select @p9s=isnull(convert(nvarchar(4000),@p9,126),''(null)'') select @p0s=isnull(convert(nvarchar(4000),@p0,126),''(null)'') end -- optimization for one line select @macro=substring(@format,1,@bs) if datalength(@format)<=@bs and charindex(@cr,@macro)=0 and charindex(''\n'',@macro)=0 begin if @format_only=1 begin if @force=1 begin -- avoid error 2787 not catched by try select @tmp=replace(@macro,''%'',''%%'') -- raiserror (''test %s and %%s'',10,1) with nowait -- test (null) and (null) if @test=0 raiserror (@tmp,10,1) with nowait insert @out select @macro end else if @test=0 print @macro end else begin select @macro=replace(@macro,''\t'',char(9)) select @macro=replace(@macro,''%t'',getdate()) if @nm=1 begin select @macro=replace(replace(@macro,''{1}'',@p1s),''{2}'',@p2s) select @macro=replace(replace(@macro,''{3}'',@p3s),''{4}'',@p4s) select @macro=replace(replace(@macro,''{5}'',@p5s),''{6}'',@p6s) select @macro=replace(replace(@macro,''{7}'',@p7s),''{8}'',@p8s) select @macro=replace(replace(@macro,''{9}'',@p9s),''{0}'',@p0s) end else begin select @macro=replace(@macro,''%d'',''%s'') select @macro=dbo.fn__printf(@macro,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p0) end if @force=1 begin select @tmp=replace(@macro,''%'',''%%'') if @test=0 raiserror (@tmp,10,1) with nowait insert @out select @macro end else begin if @test=0 print @macro insert @out select @macro end end -- format goto dispose end -- less than @bs declare @params table (id int identity(1,1), macro sql_variant) -- ===================================================================== init == select @format_only=isnull(@format_only,0),@force=isnull(@force,1) if @format_only=0 and not ( @p1 is null and @p2 is null and @p3 is null and @p4 is null and @p5 is null and @p6 is null and @p7 is null and @p8 is null and @p9 is null and @p0 is null) begin insert @params(macro) select isnull(@p1,''(null)'') insert @params(macro) select isnull(@p2,''(null)'') insert @params(macro) select isnull(@p3,''(null)'') insert @params(macro) select isnull(@p4,''(null)'') insert @params(macro) select isnull(@p5,''(null)'') insert @params(macro) select isnull(@p6,''(null)'') insert @params(macro) select isnull(@p7,''(null)'') insert @params(macro) select isnull(@p8,''(null)'') insert @params(macro) select isnull(@p9,''(null)'') insert @params(macro) select isnull(@p0,''(null)'') end -- macros -- ======================== identify row separator and create splitting table == select top 1 @i=charindex(@cr,@format),@j=charindex(@lf,@format) if @i is null begin select @ret=-2 goto ret end if @i>0 and @j=0 select @crlf=@cr if @i=0 and @j>0 select @crlf=@lf if @i=@j+1 select @crlf=@lf+@cr -- else is @crlf -- piece of code from sp__write_ntext_to_lines select top 1 @i=1,@p=1,@j=1,@n=datalength(@format)/2 while 1=1 begin select @i=charindex(@crlf,substring(@format,@j,4000)) select @i1=charindex(''\n'',substring(@format,@j,4000)) if @i1>0 and (@i1<@i or @i=0) select @i=@i1,@sep=''\n'' else select @sep=@crlf if @i=0 begin -- if @dbg=1 exec sp__printf ''j:%d, i:%d, @n:%d'',@j,@i,@n if @n>=@j/*+@lcrlf*/-1 insert @lines select @j,@n-@j+1 break end -- if @dbg=1 exec sp__printf ''j:%d, i:%d'',@j,@i if @icrlf=1 or @i-len(@sep)+1<0 insert @lines select @j,@i else insert @lines select @j,@i-len(@sep)+1-- 130416\s.zaglio select @j=@j+@i+len(@sep)-1 end -- while -- ============================================================== print lines == if @dbg=1 select * from @lines select @i=1 -- macro index declare cs cursor local for select leng,substring(@format,pos,leng) line from @lines -- where leng>0 order by pos open cs while 1=1 begin fetch next from cs into @k,@macro if @@fetch_status!=0 break if @macro='''' begin if @test=0 raiserror (@crlf,10,1) with nowait insert @out select '''' continue end if @format_only=0 begin select @macro=replace(@macro,''\t'',char(9)) select @macro=replace(@macro,''%t'',getdate()) if @nm=1 begin select @macro=replace(replace(@macro,''{1}'',@p1s),''{2}'',@p2s) select @macro=replace(replace(@macro,''{3}'',@p3s),''{4}'',@p4s) select @macro=replace(replace(@macro,''{5}'',@p5s),''{6}'',@p6s) select @macro=replace(replace(@macro,''{7}'',@p7s),''{8}'',@p8s) select @macro=replace(replace(@macro,''{9}'',@p9s),''{0}'',@p0s) end else begin select @macro=replace(@macro,''%d'',''%s'') select @i1=charindex(''%s'',@macro) while @i1>0 begin if @dbg=1 raiserror(''macro=%s, i1=%d, i=%d'',10,1,@macro,@i1,@i) select top 1 @macro= left(@macro,@i1-1)+ isnull(convert(nvarchar(4000),macro),''(null)'')+ substring(@macro,@i1+2,4000) from @params where id=@i select @i1=charindex(''%s'',@macro,@i1+2),@i=@i+1 if @i>11 goto err_out end end -- macro replace end -- format_only if @force=1 and @format_only=0 begin -- raiserror has a limit of 200-255 chars if @k<=@bs begin -- print @macro select @tmp=replace(@macro,''%'',''%%'') if @test=0 raiserror (@tmp,10,1) with nowait insert @out select @macro end else begin -- split into @bs char''s line while @k>@bs begin select @i1=@bs while (@i1>0 and not substring(@macro,@i1,1) in ('' '',''='','':'',''|'','','','';'') ) select @i1=@i1-1 if @i1=0 select @i1=@bs select @tmp=substring(@macro,1,@i1) insert @out select @tmp if @format_only=0 select @tmp=replace(@tmp,''%'',''%%'') if @test=0 raiserror (@tmp,10,1) with nowait select @macro=substring(@macro,@i1+1,4000) select @k=len(@macro) end -- while k=len end end -- forse=1 and fmt_only=0 else begin if @test=0 print @macro insert @out select @macro end end -- while of cursor close cs deallocate cs select @ret=0 -- return printed strings to @format dispose: select @format = ( (select line+@crlf from @out for xml path(''''),type).value(''.'',''nvarchar(max)'') ) goto ret -- ===================================================================== errs == err_out: exec sp__err ''too many %?'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope print a formatted string using raiserror(10) to ensure immediate output to well track the code execution. raiserror has a limit of 200/240 chars so the sp__printf break longs string into chunks trying to respect spaces and punctuations See also sp__printframe,sp__printsql Parameters @format uses same C definitions with some limits %s marker for a string %d marker for a number %t expandend into date-time {1},{2},{...} are specifically replaced by @p1,@p2,... return the formatted string @p1..@p0 replaces %s,%d,... @opt options fo format only :do not apply %s,%d,... replacement print print instead of raiserror to force output; print is faster because enqueue but the output do not appear after the sql command; raiserror flush immediatelly the output buffer; test do not output, used by sp__printf_test or to format '' select @ret=-1 ret: return @ret end -- sp__printf' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__printf: -- ============================================================= sp__printf_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__printf_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130725 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__printf_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__printf_test') with nowait goto skip_sp__printf_test end if @ver>130725 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__printf_test') with nowait goto skip_sp__printf_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__printf_test') with nowait if exists( select top 1 null from sys.objects where name='sp__printf_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__printf_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:sp__printf,test v:130725\s.zaglio: updated v:130607\s.zaglio: final ok message and managed option v:130606\s.zaglio: done r:130605\s.zaglio: test for sp__printf t:sp__printf_test @opt=''run'',@dbg=1 t:sp__printf_test @opt=''run|managed'',@dbg=1 */ CREATE proc sp__printf_test @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @id int,@tst nvarchar(max),@rst nvarchar(max),@otst nvarchar(max), @p1 sql_variant,@p2 sql_variant,@p3 sql_variant,@p4 sql_variant, @run bit,@ok bit,@v nvarchar(max),@i int,@crlf nvarchar(2), @n int,@nok int,@managed bit,@d datetime declare @test table ( id int, tst nvarchar(max), p1 sql_variant null, p2 sql_variant null, p3 sql_variant null, p4 sql_variant null, opt sysname null, rst nvarchar(max) ) -- =========================================================== initialization == select @nok=0, @n=0, @crlf=crlf, @run=isnull(charindex(''|run|'',@opt),0), @managed=isnull(charindex(''|managed|'',@opt),0), @d=getdate() from fn__sym() -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == insert @test(id,tst,rst) select 10, ''simple test'', ''simple test'' insert @test(id,tst,rst) select 20, ''line one\nline two'', ''line one line two'' insert @test(id,tst,rst) select 30, ''line one\n\nline two\n'', ''line one line two '' insert @test(id,tst,rst) select 40, '''', '''' insert @test(id,tst,p1,p2,p3,rst) select 50, ''today:%t\np1=%s\np2=%d\np3=%s'',1,''two'',3, ''today:% p1=1 p2=two p3=3'' insert @test(id,tst,opt,rst) select 60,''test %s format %d only %t'',''fo'', ''test %s format %d only %t'' insert @test(id,tst,p1,p2,rst) select 70,''%s\n%s'',''test1'',''test2'', ''test1 test2'' insert @test(id,tst,p1,p2,p3,rst) select 80,''test {1}\ntest {2}'',''t1'',''t2'',''t3'', ''test t1 test t2'' insert @test(id,tst,p1,p2,rst) select 84,''test (%s,%s)'',''%drop%'',''%drop%'', ''test (%drop%,%drop%)'' insert @test(id,tst,p1,rst) select 85,''hex test %x'',-1, ''hex test 0xffffffff'' insert @test(id,tst,p1,rst) select 86,''hex test %x'',123123123123123, ''hex test 0x0f000001b37304d6fa6f0000'' insert @test(id,tst,p1,p2,p3,p4,rst) select 87,''%s%s%s%s'',''test('','''',12,'')'', ''test(12)'' insert @test(id,tst,p1,p2,p3,rst) select 88,''%%%s%%%s%%%s%%'',''test('','''','')'', ''%test(%%)%'' -- mega test select @i=10000,@v=''start\n'' while (@i>0) select @v=@v+''01234567890\n'',@i=@i-1 select @v=@v+''end'' insert @test(id,tst,rst) select 90,@v,replace(@v,''\n'',@crlf) -- test with lines of more than 200 chars select @v=''start\n'' select @i=20 while (@i>0) select @v=@v+''0123456789;'',@i=@i-1 select @i=20 while (@i>0) select @v=@v+''01234567890'',@i=@i-1 select @v=@v+''\nend'' insert @test(id,tst,rst) select 100,@v, ''start 0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789;0123456789; 0123456789;0123456789; 01234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001 end'' if @run=0 goto help -- sp__printf_test @dbg=2 -- the output of printf add virtually the last crlf of the out of console update @test set rst=rst+@crlf -- ================================================================ run tests == declare cs cursor local for select id,tst,p1,p2,p3,p4,opt,rst from @test open cs while 1=1 begin fetch next from cs into @id,@otst,@p1,@p2,@p3,@p4,@opt,@rst if @@fetch_status!=0 break select @n=@n+1 if @dbg>0 exec sp__prints @id select @tst=@otst select @opt=case when @managed=1 or @dbg=0 then ''test|'' else '''' end +isnull(@opt,'''') exec sp__printf @tst out,@p1,@p2,@p3,@p4,@opt=@opt select @ok=0 if @tst is null begin select @err_msg=''error in sp__printf for %s'' raiserror(@err_msg,11,1,@otst) if @ret=0 exec @ret=sp__err @err_msg,@opt=''noerr'' end if charindex(''%t'',@otst)>0 and charindex(''|fo'',@opt)=0 begin if @dbg>2 exec sp__printf ''-- tst like'' if @tst like @rst select @ok=1 end else begin if @dbg>2 exec sp__printf ''-- tst eq'' if @tst=@rst select @ok=1 end if @ok=0 begin select @err_msg=''^^ failed test %d'' select @ret=@id if @managed=1 break raiserror(@err_msg,11,1,@id) if @dbg>0 begin select @tst=replace(replace(@tst,char(13),''\r''),char(10),''\n''), @rst=replace(replace(@rst,char(13),''\r''),char(10),''\n'') raiserror(''^^ test %d:"%s" failed with:"%s"'',11,1,@id,@tst,@rst) end end else select @nok=@nok+1 end -- cursor cs close cs deallocate cs if @dbg>0 exec sp__prints ''end'' if @managed=0 exec sp__elapsed @d,''%d/%d tests passed'',@v1=@nok,@v2=@n -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope check know formats of sp__printf Parameters @opt options run run tests managed when used by caller, stop at 1st error and return the id @dbg 1=show passages info 3=show dbg info '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__printf_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__printf_test: -- ============================================================== sp__printframe select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__printframe',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130605 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__printframe') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__printframe') with nowait goto skip_sp__printframe end if @ver>130605 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__printframe') with nowait goto skip_sp__printframe end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__printframe') with nowait if exists( select top 1 null from sys.objects where name='sp__printframe' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__printframe] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility todo: manage @level v:130605\s.zaglio: removed sp__printf parameters v:110701\s.zaglio: added @out v:110624\s.zaglio: added multiline comment v:100723\s.zaglio: added code style v:100626\s.zaglio: print a well visible comment also in code style t:sp__printframe ''this is a test'' t:sp__printframe ''this is a code comment'',# t: create table #src(lno int identity,line nvarchar(4000)) exec sp__printframe ''#src test'',@out=''#src'' select * from #src drop table #src */ CREATE proc sp__printframe @format nvarchar(4000)=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @level smallint=null, @out sysname =null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @format is null goto help declare @r nvarchar(4000),@l1 nvarchar(240),@l2 nvarchar(240),@l int, @crlf nvarchar(2),@l3 nvarchar(240), @l4 nvarchar(240) -- select @crlf=crlf from fn__sym() if @out is null begin -- multiline comment if charindex(''%s'',@format)=0 and charindex(''%d'',@format)=0 and not @p1 is null begin exec sp__printf '''' exec sp__printf ''-- ##########################'' -- col 30 exec sp__printf ''-- ##'' select @r=''-- ## ''+@format if not @p1 is null select @l1=''-- ## ''+convert(nvarchar(240),@p1) if not @p2 is null select @l2=''-- ## ''+convert(nvarchar(240),@p2) if not @p3 is null select @l3=''-- ## ''+convert(nvarchar(240),@p3) if not @p4 is null select @l4=''-- ## ''+convert(nvarchar(240),@p4) exec sp__printf @r if not @l1 is null exec sp__printf @l1 if not @l2 is null exec sp__printf @l2 if not @l3 is null exec sp__printf @l3 if not @l4 is null exec sp__printf @l4 exec sp__printf ''-- ##'' exec sp__printf ''-- ########################################################'' -- col 60 goto ret end if coalesce(@p1,'''')!=''#'' begin select @format=''-- ## ''+@format select @r=dbo.fn__printf(@format,@p1,@p2,@p3,@p4,null,null,null,null,null,null) exec sp__printf '''' exec sp__printf ''-- ##########################'' -- col 30 exec sp__printf ''-- ##'' exec sp__printf @r exec sp__printf ''-- ##'' exec sp__printf ''-- ########################################################'' -- col 60 end else begin -- sp__printframe ''this is a code comment'',# select @r=''exec sp__printframe ''''''+ dbo.fn__printf(@format,@p1,@p2,@p3,@p4,null,null,null,null,null,null)+ '''''' -- ##'' select @l=len(@r) select @l1=''-- ''+replicate(''#'',@l-3) select @l2=''-- ################''+replicate('' '',@l-21)+''##'' exec sp__printf '''' exec sp__printf @l1 exec sp__printf @l2 raiserror(@r,10,1) exec sp__printf @l2 exec sp__printf @l1 end end -- @out is null else begin -- out to table if @out!=''#src'' or object_id(''tempdb..#src'') is null goto err_out -- multiline comment if charindex(''%s'',@format)=0 and charindex(''%d'',@format)=0 and not @p1 is null begin insert #src(line) select ''-- ##########################'' -- col 30 insert #src(line) select ''-- ##'' select @r=''-- ## ''+@format if not @p1 is null select @l1=''-- ## ''+convert(nvarchar(240),@p1) if not @p2 is null select @l2=''-- ## ''+convert(nvarchar(240),@p2) if not @p3 is null select @l3=''-- ## ''+convert(nvarchar(240),@p3) if not @p4 is null select @l4=''-- ## ''+convert(nvarchar(240),@p4) insert #src(line) select @r if not @l1 is null insert #src(line) select @l1 if not @l2 is null insert #src(line) select @l2 if not @l3 is null insert #src(line) select @l3 if not @l4 is null insert #src(line) select @l4 insert #src(line) select ''-- ##'' insert #src(line) select ''-- ########################################################'' -- col 60 goto ret end if coalesce(@p1,'''')!=''#'' begin select @format=''-- ## ''+@format select @r=dbo.fn__printf(@format,@p1,@p2,@p3,@p4,null,null,null,null,null,null) insert #src(line) select '''' insert #src(line) select ''-- ##########################'' -- col 30 insert #src(line) select ''-- ##'' insert #src(line) select @r insert #src(line) select ''-- ##'' insert #src(line) select ''-- ########################################################'' -- col 60 end else begin -- sp__printframe ''this is a code comment'',# select @r=''exec sp__printframe ''''''+ dbo.fn__printf(@format,@p1,@p2,@p3,@p4,null,null,null,null,null,null)+ '''''' -- ##'' select @l=len(@r) select @l1=''-- ''+replicate(''#'',@l-3) select @l2=''-- ################''+replicate('' '',@l-21)+''##'' insert #src(line) select '''' insert #src(line) select @l1 insert #src(line) select @l2 insert #src(line) select @r insert #src(line) select @l2 insert #src(line) select @l1 end end goto ret -- =================================================================== errors == err_out: exec @ret=sp__err ''Only #src is admitted or %s not found'',@proc,@p1=@out -- ===================================================================== help == help: exec sp__usage @proc,'' Scope print a well visible comment also in code style Parameters @format same of sp__printf (%s,%d,%t are markers for @p1,@p2...) @p1 if @p1 is ''''#'''', the title is printed in code style to integrate into code Examples '' exec sp__printf ''\n sp__printframe ''''this is a test'''' -- produces:'' exec sp__printframe ''this is a test'' exec sp__printf ''\n sp__printframe ''''this is a code comment'''',# -- produces:'' exec sp__printframe ''this is a code comment'',# select @ret=-1 ret: return @ret end -- sp__printframe' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__printframe: -- ================================================================== sp__prints select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__prints',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130612.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__prints') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__prints') with nowait goto skip_sp__prints end if @ver>130612.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__prints') with nowait goto skip_sp__prints end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__prints') with nowait if exists( select top 1 null from sys.objects where name='sp__prints' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__prints] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130612.1000\s.zaglio: addapted to fn__prints v:130611\s.zaglio: extended 8< macro v:130107\s.zaglio: added 8< macro comment v:120921\s.zaglio: added @p1,... v:110329\s.zaglio: added use of | v:100723\s.zaglio: print a separator for better code reading t:sp__prints ''errors|help|8<|8140203 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__printsql') with nowait goto skip_sp__printsql end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__printsql') with nowait if exists( select top 1 null from sys.objects where name='sp__printsql' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__printsql] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140203\s.zaglio: bug near some end lines v:130729\s.zaglio: bug near % v:130530\s.zaglio: complete r:130529\s.zaglio: removed #src, using splitter, added @opt v:110518\s.zaglio: added more @sql... v:110315\s.zaglio: print sql code refactored t: declare @sql nvarchar(max) select @sql=''''''''+replace(definition,'''''''','''''''''''')+'''''''' from sys.sql_modules where object_id=object_id(''sp__printsql'') exec sp__printsql @sql */ CREATE proc sp__printsql @sql1 ntext = null, @sql2 ntext = null, @sql3 ntext = null, @sql4 ntext = null, @opt sysname = 0, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- ========================================================= param formal chk == if @sql1 is null and @sql2 is null and @sql3 is null and @sql4 is null goto help -- ============================================================== declaration == declare @sql nvarchar(max),@line nvarchar(4000),@crlf nvarchar(2), @i int,@j int,@n int,@lcrlf tinyint -- =========================================================== initialization == select @sql=cast(@sql1 as nvarchar(max)) +isnull(@crlf+cast(@sql2 as nvarchar(max)),'''') +isnull(@crlf+cast(@sql3 as nvarchar(max)),'''') +isnull(@crlf+cast(@sql4 as nvarchar(max)),''''), @crlf=crlf, @lcrlf=len(crlf) from fn__sym() -- ======================================================== second params chk == -- ===================================================================== body == -- if substring(@sql1,1,4)=''#src'' exec sp__print_table ''#src'' select @n=len(@sql),@i=1,@j=charindex(@crlf,@sql,@i) while 1=1 begin -- exec sp__printf ''i=%d, j=%d'',@i,@j if @j=0 select @j=@n+1 select @line=replace(substring(@sql,@i,@j-@i),''%'',''%%''),@j=@j+@lcrlf,@i=@j raiserror(@line,10,1) if @j>@n break select @j=charindex(@crlf,@sql,@i) end goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope print long sql code eventually refactored (TODO: today this is only a marker for future full functional sp) Parameters @sql1..4 sql code @opt options (not used) '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__printsql' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__printsql: -- =============================================================== sp__proc_stop select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__proc_stop',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091026 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__proc_stop') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__proc_stop') with nowait goto skip_sp__proc_stop end if @ver>091026 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__proc_stop') with nowait goto skip_sp__proc_stop end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__proc_stop') with nowait if exists( select top 1 null from sys.objects where name='sp__proc_stop' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__proc_stop] begin try exec dbo.sp_executesql @statement = N'/* leave this v:091026\s.zaglio: stop or show how to breack run of code without close connection c:this is only to not loose too much time to read,understand,verify the manual g:utility */ CREATE proc sp__proc_stop @proc sysname=null,@msg sysname=null,@severity int=17 as begin if @proc is null or @msg is null goto help raiserror(''%s:%s'',@severity,1,@proc,@msg) help: exec sp__usage ''sp__proc_stop'' end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__proc_stop: -- ================================================================= sp__profile select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__profile',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130630 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__profile') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__profile') with nowait goto skip_sp__profile end if @ver>130630 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__profile') with nowait goto skip_sp__profile end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__profile') with nowait if exists( select top 1 null from sys.objects where name='sp__profile' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__profile] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility d:130630\s.zaglio: sp__util_profile v:130630\s.zaglio: refactor v:101130\s.zaglio: Self adjusting trace to capture worst performing TSQL c:http://sqlserverperformance.idera.com/tsql-optimization/finding-heaviest-tsql-optimize-sql-server/ t:sp__profile 2,@dbg=1 t:xp_cmdshell ''dir f:\sqldata\*.*'' */ CREATE proc sp__profile @MaxTraceTimeInMinutes smallint = null, @MinTraceTimeInMinutes smallint = null, @dbg smallint = 0 as begin set nocount on declare @proc sysname, @ret int select @proc=object_name(@@procid),@ret=0 if nullif(@MaxTraceTimeInMinutes,0) is null goto help select @MinTraceTimeInMinutes=isnull(@MinTraceTimeInMinutes, @MaxTraceTimeInMinutes*0.75) exec sp__printf ''Will run for %d minutes, please do not stop'', @MaxTraceTimeInMinutes set transaction isolation level read uncommitted set lock_timeout 20000 set implicit_transactions off if @@trancount > 0 commit transaction set language us_english set cursor_close_on_commit off set query_governor_cost_limit 0 set numeric_roundabort off declare @spid int, @databaseid int, @applicationname nvarchar(256), @tridl int, @trids int, @trstatusl int, @trstatuss int, @tracepathl nvarchar(1024), @tracepaths nvarchar(1024), @tracetablelong nvarchar(1024), @tracetableshort nvarchar(1024), @currentduration bigint, @oldduration bigint, @tracerowsfound int, @maxtracefilesize bigint, @laststmtendtime datetime, @lastsampletime datetime, @laststmtendtimes datetime, @lastsampletimes datetime, @secsincelastcollection int, @bypasscollection bit, @shorttraceexists bit, @estimated bit, @bitone bit, @gatherwaittimeinsecs tinyint, @nooftsqlstmtsperminhighwater int, @nooftsqlstmtsperminlowwater int, @mindurationforlongtrace bigint, @mindurationforshorttrace bigint, @starttracetime datetime, @uniquetsql int, @statisticaldeviation dec(14,4), @statisticallastaverageduration bigint, @statisticalaverageduration bigint, @statisticalsamplesize int, @statisticalminimumpopulation int, @execstring varchar(50), @textdata nvarchar(4000), @duration bigint, @endtime datetime, @reads bigint, @writes bigint, @cpu int, @entrydatebucket int, @multiplierthisrow int, @multiplier int, @position int, @asciiposition int, @tsqlhashcode bigint, @multilineskip tinyint, @singlelineskip tinyint, @twocharacter char(2), @onecharacterascii int, @previoushighduration bigint select @spid = @@spid, @currentduration = 5000000, @maxtracefilesize = 25, -- in mb @nooftsqlstmtsperminhighwater = 500, --- (per minute) this number for testing, normally would be perhaps 200 @nooftsqlstmtsperminlowwater = 150, --- (per minute) this number for testing, normally would be perhaps 30 @mindurationforlongtrace = 80000, -- overlap point between high and low traces (in microseconds) @mindurationforshorttrace = 1, -- in minutes @starttracetime = getdate(), @uniquetsql = 0, @statisticaldeviation = 100, @statisticalsamplesize = 30, @statisticalminimumpopulation = 300, @bitone = 1 --the io path to tempdb on high-end systems will be san, hence we should put the trace data files there too rather than on a local drive -- use tempdb select @tracepathl = left(physical_name, len(physical_name) - charindex(''\'',reverse(physical_name))) + ''\'' from sys.database_files where file_id = 1 select @tracepaths = @tracepathl + ''heaviestshorttrace'' select @tracepathl = @tracepathl + ''heaviestlongtrace'' if @dbg>1 begin -- exec sp_trace_setstatus 2, 0 -- stop trace -- exec sp_trace_setstatus 3, 2 -- close trace select ''exec sp_trace_setstatus ''+convert(nvarchar(2),traceid)+'', 2 -- close the long trace'' sql,* -- select * from sys.fn_trace_getinfo(0) where property = 2 and convert(nvarchar(1024),value) like ''%\heaviest%trace%'' select [name] from tempdb..sysobjects where [name] like ''##%'' end gather: exec sp__printf ''%t gathering...'',''%t'' select @bypasscollection = 0, @laststmtendtime = getdate(), @lastsampletime = getdate(), @laststmtendtimes = getdate(), @lastsampletimes = getdate(), @gatherwaittimeinsecs = 30 if @dbg>1 select traceid,value,@tracepaths tps,@tracepathl tpl from sys.fn_trace_getinfo(0) where property=2 select @trids = traceid from sys.fn_trace_getinfo(0) where property = 2 and convert(nvarchar(1024),value) like @tracepaths+''%'' if @@rowcount <> 0 select @shorttraceexists = 1 else select @shorttraceexists = 0 select @tridl = traceid -- select * from sys.fn_trace_getinfo(0) where property = 2 and convert(nvarchar(1024),value) like @tracepathl+''%'' if @@rowcount <> 0 goto longtraceexists createlongtrace: select @bypasscollection = 1 if @dbg=1 begin if @tridl is null exec sp__printf ''+--creating long trace'' else exec sp__printf ''+--reopening long trace'' end exec sp_trace_create @tridl output, 2, @tracepathl, @maxtracefilesize, null, 10 if @dbg=1 exec sp__printf '' +--long trace %d in %s'',@tridl,@tracepathl if @shorttraceexists = 0 begin if @dbg=1 begin if @tridl is null exec sp__printf ''+--creating short trace'' else exec sp__printf ''+--reopening short trace'' end exec sp_trace_create @trids output, 2, @tracepaths, @maxtracefilesize, null, 10 if @dbg=1 exec sp__printf '' +--short trace %d in %s'',@trids,@tracepaths end --select trace columns to show for completed statements on long trace exec sp_trace_setevent @tridl, 41, 1, @bitone -- textdata exec sp_trace_setevent @tridl, 41, 3, @bitone -- dbid exec sp_trace_setevent @tridl, 41, 10, @bitone -- applicationname exec sp_trace_setevent @tridl, 41, 12, @bitone --spid exec sp_trace_setevent @tridl, 41, 13, @bitone -- duration in microseconds exec sp_trace_setevent @tridl, 41, 15, @bitone -- endtime exec sp_trace_setevent @tridl, 41, 16, @bitone --diskreadslogical exec sp_trace_setevent @tridl, 41, 17, @bitone --diskwritesphysical exec sp_trace_setevent @tridl, 41, 18, @bitone --cpu time --select trace columns to show for completed sp statements on long trace exec sp_trace_setevent @tridl, 45, 1, @bitone -- textdata exec sp_trace_setevent @tridl, 45, 3, @bitone -- dbid exec sp_trace_setevent @tridl, 45, 10, @bitone -- applicationname exec sp_trace_setevent @tridl, 45, 12, @bitone --spid exec sp_trace_setevent @tridl, 45, 13, @bitone -- duration in microseconds exec sp_trace_setevent @tridl, 45, 15, @bitone -- endtime exec sp_trace_setevent @tridl, 45, 16, @bitone --diskreadslogical exec sp_trace_setevent @tridl, 45, 17, @bitone --diskwritesphysical exec sp_trace_setevent @tridl, 45, 18, @bitone --cpu time if @shorttraceexists = 0 begin --select trace columns to show for completed statements on short trace exec sp_trace_setevent @trids, 41, 1, @bitone -- textdata exec sp_trace_setevent @trids, 41, 3, @bitone -- dbid exec sp_trace_setevent @trids, 41, 10, @bitone -- applicationname exec sp_trace_setevent @trids, 41, 12, @bitone --spid exec sp_trace_setevent @trids, 41, 13, @bitone -- duration in microseconds exec sp_trace_setevent @trids, 41, 15, @bitone -- endtime exec sp_trace_setevent @trids, 41, 16, @bitone --diskreadslogical exec sp_trace_setevent @trids, 41, 17, @bitone --diskwritesphysical exec sp_trace_setevent @trids, 41, 18, @bitone --cpu time --select trace columns to show for completed sp statements on short trace exec sp_trace_setevent @trids, 45, 1, @bitone -- textdata exec sp_trace_setevent @trids, 45, 3, @bitone -- dbid exec sp_trace_setevent @trids, 45, 10, @bitone -- applicationname exec sp_trace_setevent @trids, 45, 12, @bitone --spid exec sp_trace_setevent @trids, 45, 13, @bitone -- duration in microseconds exec sp_trace_setevent @trids, 45, 15, @bitone -- endtime exec sp_trace_setevent @trids, 45, 16, @bitone --diskreadslogical exec sp_trace_setevent @trids, 45, 17, @bitone --diskwritesphysical exec sp_trace_setevent @trids, 45, 18, @bitone --cpu time end --set filters exec sp_trace_setfilter @tridl, 13, 0, 4, @currentduration -- set duration of long trace >= exec sp_trace_setfilter @tridl, 12, 0, 1, @spid -- dont trace this spid''s actions if @shorttraceexists = 0 begin exec sp_trace_setfilter @trids, 13, 0, 3, @mindurationforlongtrace -- set duration of short trace < long trace exec sp_trace_setfilter @trids, 13, 0, 4, @mindurationforshorttrace -- set duration of short trace >=1 exec sp_trace_setfilter @trids, 12, 0, 1, @spid -- dont trace this spid''s actions end longtraceexists: if (select count(*) from tempdb..sysobjects where name like ''%heaviesttracesave%'') <> 0 begin select @laststmtendtime = laststmtendtime, @lastsampletime = lastsampletime, @laststmtendtimes = laststmtendtimes, @lastsampletimes = lastsampletimes from ##heaviesttracesave end else begin create table ##heaviesttracesave(laststmtendtime datetime, lastsampletime datetime, laststmtendtimes datetime, lastsampletimes datetime) insert into ##heaviesttracesave values (getdate(), getdate(), getdate(), getdate()) end if @bypasscollection = 1 goto bypasscollection -- process deep infrequent "short" trace exec sp_trace_setstatus @trids, 1 -- start the short trace waitfor delay ''00:00:01'' -- give the short trace exactly a second to run exec sp_trace_setstatus @trids, 0 -- stop the short trace -- trace file processing and consolidation starts here if (select count(*) from tempdb..sysobjects where name like ''%heaviesttraceusage%'') = 0 create table ##heaviesttraceusage( [tsqlhashcode] [bigint] not null, [databaseid] [int] not null, [noofruns] [int] not null, [estimated] [bit] not null, [totcpu] [bigint] not null, [totio] [bigint] not null, [totduration] [bigint] not null, [highduration] [bigint] not null, [applicationname] [nvarchar] (256) null, [tsqltext] [nvarchar](4000) not null, constraint [pk_traceusage] primary key clustered ( [tsqlhashcode] asc, [databaseid] asc)) -- with (data_compression = page) sql 2008 only select @multiplier = datediff(second, @lastsampletimes, getdate()) if @multiplier < 1 select @multiplier = 1 select @tracerowsfound = 0 select top 1 @tracetablelong=convert(nvarchar(512),value) from sys.fn_trace_getinfo(0) where property = 2 and traceid=@tridl select top 1 @tracetableshort=convert(nvarchar(512),value) from sys.fn_trace_getinfo(0) where property = 2 and traceid=@trids -- select @tracetablelong = @tracepathl + ''.trc'', -- @tracetableshort = @tracepaths + ''.trc'' declare traceoutput cursor fast_forward for select 0, textdata, databaseid, applicationname, duration, endtime, reads, writes, cpu from fn_trace_gettable(@tracetablelong, default) where duration > @mindurationforlongtrace and endtime > @laststmtendtime and textdata is not null union all select 1, textdata, databaseid, applicationname, duration, endtime, reads, writes, cpu from fn_trace_gettable(@tracetableshort, default) where duration > 0 and endtime > @laststmtendtimes and textdata is not null open traceoutput fetch next from traceoutput into @estimated, @textdata, @databaseid, @applicationname, @duration, @endtime, @reads, @writes, @cpu while @@fetch_status = 0 begin -- i have used a simple checksum hash for the tsqlhashcode col after stripping off the parameters -- but the actual tsql is saved in the tracetsql table with parameters for easy evaluation select @textdata = ltrim(rtrim(@textdata)), @position = 1, @asciiposition = 1, @tsqlhashcode = 0, @multilineskip = 0, @singlelineskip = 0 while @position <= len(@textdata) begin select @twocharacter = substring(@textdata, @position, 2) if @twocharacter = ''/*'' collate sql_latin1_general_cp1_ci_as and @singlelineskip = 0 begin set @multilineskip = 1 set @position = @position + 2 continue end if @twocharacter = ''*/'' collate sql_latin1_general_cp1_ci_as and @singlelineskip = 0 begin set @multilineskip = 0 set @position = @position + 2 continue end if @twocharacter = ''--'' collate sql_latin1_general_cp1_ci_as and @multilineskip = 0 begin set @singlelineskip = 1 set @position = @position + 2 continue end select @onecharacterascii = ascii(substring(upper(@twocharacter), 1, 1)) if (@onecharacterascii between 10 and 13) and @multilineskip = 0 begin set @singlelineskip = 0 set @position = @position + 1 continue end if @multilineskip = 0 and @singlelineskip = 0 and @onecharacterascii <> 32 select @tsqlhashcode = @tsqlhashcode + (@onecharacterascii * @asciiposition) set @position = @position + 1 if @onecharacterascii <> 32 set @asciiposition = @asciiposition + 1 end if @estimated = 0 begin select @multiplierthisrow = 1 select @tracerowsfound = @tracerowsfound + 1 if @endtime > @laststmtendtime select @laststmtendtime = @endtime end else select @multiplierthisrow = @multiplier if @endtime > @laststmtendtimes select @laststmtendtimes = @endtime select @previoushighduration = highduration from ##heaviesttraceusage where tsqlhashcode = @tsqlhashcode and databaseid = @databaseid if @@rowcount = 0 begin insert into ##heaviesttraceusage values (@tsqlhashcode, @databaseid, @multiplierthisrow, @estimated, (@cpu * @multiplierthisrow), ((@reads + @writes) * @multiplierthisrow), (@duration * @multiplierthisrow), @duration, @applicationname, @textdata) select @uniquetsql = @uniquetsql + 1 end else if @duration > @previoushighduration begin update ##heaviesttraceusage set noofruns = ##heaviesttraceusage.noofruns + @multiplierthisrow, totcpu = totcpu + (@cpu * @multiplierthisrow), totio = totio + ((@reads + @writes) * @multiplierthisrow), totduration = totduration + (@duration * @multiplierthisrow), highduration = @duration, tsqltext = @textdata where tsqlhashcode = @tsqlhashcode and databaseid = @databaseid end else update ##heaviesttraceusage set noofruns = ##heaviesttraceusage.noofruns + @multiplierthisrow, totcpu = totcpu + (@cpu * @multiplierthisrow), totio = totio + ((@reads + @writes) * @multiplierthisrow), totduration = totduration + (@duration * @multiplierthisrow) where tsqlhashcode = @tsqlhashcode and databaseid = @databaseid fetch next from traceoutput into @estimated, @textdata, @databaseid, @applicationname, @duration, @endtime, @reads, @writes, @cpu end close traceoutput deallocate traceoutput update ##heaviesttracesave set laststmtendtime = @laststmtendtime, lastsampletime = getdate(), laststmtendtimes = @laststmtendtimes, lastsampletimes = getdate() if @dbg=1 exec sp__printf ''get current duration from long trace'' select @currentduration = convert(int,value) -- select * from fn_trace_getfilterinfo(0) from fn_trace_getfilterinfo(@tridl) where columnid = 13 ; -- get current duration select @secsincelastcollection = datediff (ss, @lastsampletime, getdate()) if (@tracerowsfound / (@secsincelastcollection / 60.00) > @nooftsqlstmtsperminhighwater) or ((@tracerowsfound / (@secsincelastcollection / 60.00) < @nooftsqlstmtsperminlowwater) and (@currentduration > @mindurationforlongtrace)) --too many or too few rows collected, adjust filter begin if @dbg=1 exec sp__printf ''stop and close long trace %d'',@tridl exec sp_trace_setstatus @tridl, 0 -- stop the trace exec sp_trace_setstatus @tridl, 2 -- close the trace select @oldduration = @currentduration if @tracerowsfound / (@secsincelastcollection / 60.00) > @nooftsqlstmtsperminhighwater begin select @gatherwaittimeinsecs = @gatherwaittimeinsecs / 5 select @currentduration = (((@tracerowsfound / (@secsincelastcollection / 60.00)) / @nooftsqlstmtsperminhighwater) * 0.25 * @currentduration) + @currentduration end else begin select @gatherwaittimeinsecs = @gatherwaittimeinsecs / 4 -- should be 3 select @currentduration = @currentduration / 1.5 if @currentduration < @mindurationforlongtrace select @currentduration = @mindurationforlongtrace end goto createlongtrace end bypasscollection: if @dbg=1 exec sp__printf ''restart long trace %d'',@tridl exec sp_trace_setstatus @tridl, 1 -- re-start the trace as it may have been stopped manually or automatically select @execstring = ''waitfor delay ''''00:00:'' + convert(varchar(2), @gatherwaittimeinsecs) + '''''''' exec (@execstring) ---derive statistical deviation if (select count(*) from tempdb..sysobjects where name like ''%heaviesttraceusage%'') <> 0 select @statisticalaverageduration = avg(totduration/noofruns) from ##heaviesttraceusage where tsqlhashcode in (select top (@statisticalsamplesize) with ties tsqlhashcode from ##heaviesttraceusage order by totduration/noofruns desc) if @statisticallastaverageduration is not null select @statisticaldeviation = abs(1 - ((@statisticalaverageduration * 1.0000) / (@statisticallastaverageduration * 1.0000))) select @statisticallastaverageduration = @statisticalaverageduration if (datediff(minute,@starttracetime, getdate()) >= @mintracetimeinminutes) and ((datediff(minute,@starttracetime, getdate()) >= @maxtracetimeinminutes) or ((@uniquetsql > @statisticalminimumpopulation) and (@statisticaldeviation < 0.03))) -- less than 3% deviation goto exitroutine goto gather exitroutine: if @dbg=1 exec sp__printf ''stop and close traces %d and %d'',@tridl,@trids exec sp_trace_setstatus @tridl, 0 -- stop the long trace exec sp_trace_setstatus @tridl, 2 -- close the long trace exec sp_trace_setstatus @trids, 0 -- stop the short trace exec sp_trace_setstatus @trids, 2 -- close the short trace if (select count(*) from tempdb..sysobjects where name like ''%heaviesttracesave%'') <> 0 drop table ##heaviesttracesave -- give statistical confidence indicator as a percentage select 100-(@statisticaldeviation*100) as [confidence %] -- show heaviest tsql (all runs) select noofruns as [number of executions], totcpu, totio, totduration as [total duration (microseconds)], highduration as [longest duration (microseconds)], totduration/noofruns as [ave duration (microseconds)], db_name(databaseid) as [database], tsqltext, applicationname from ##heaviesttraceusage order by 4 desc drop table ##heaviesttraceusage goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope Two level - Self adjusting trace to capture worst performing TSQL statements using a sampling technique Output is stored in a table which is finally output once statistical confidence is high enough or sample time expires Notes - originally from http://sqlserverperformance.idera.com/tsql-optimization/finding-heaviest-tsql-optimize-sql-server/ Parameters @MaxTraceTimeInMinutes routine may exit sooner if enough samples have been gathered (normally 20 minutes) @MinTraceTimeInMinutes (optional) minimum time to run even if statistics have "settled" (normally 75%:15 minutes) Examples exec sp__profile 20 '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__profile' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__profile: -- ============================================================= sp__profile_sql select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__profile_sql',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130630 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__profile_sql') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__profile_sql') with nowait goto skip_sp__profile_sql end if @ver>130630 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__profile_sql') with nowait goto skip_sp__profile_sql end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__profile_sql') with nowait if exists( select top 1 null from sys.objects where name='sp__profile_sql' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__profile_sql] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,nomssql2k d:130630\s.zaglio: sp__util_sqltrace v:130630\s.zaglio: renamed and small refactor v:100810\s.zaglio: originally from http://www.sommarskog.se/index.html t: exec sp__profile_sql '' exec sp__printf ''''test'''' select top 1000 * from sysobjects '' */ CREATE procedure sp__profile_sql @batch nvarchar(max) = null, -- sql batch to analyse @minreads bigint = 1, -- min reads (logical) @mincpu int = 0, -- min cpu time (milliseconds) @minduration bigint = 0, -- min duration (microseconds) @factor varchar(50) = ''duration'', -- % (duration, reads, writes, cpu) @order varchar(50) = '''', -- order (duration, reads, writes, cpu) @plans varchar(50) = '''', -- include query plans - intentive (actual, estimated) @rollback bit = 0, -- run in a transaction and rollback @timeout int = 300 -- set a maximum trace duration (seconds) as begin set nocount on; declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @batch is null goto help declare @id int, @spid int, @file nvarchar(256), @fsize bigint, @plan int, @on bit, @rc int, @stoptime datetime, @total int, @rccpu int, @rcduration int select @spid = @@spid, @on = 1, @fsize = 5, @plan = case lower(@plans) when ''actual'' then 146 when ''estimated'' then 122 end, @stoptime = dateadd(second, @timeout, getdate()) exec sp__get_temp_dir @file out select @file = @file+''\''+cast(newid() as char(36)) exec sp_trace_create @id output, 2, @file, @fsize, @stoptime if @plan is not null begin exec sp_trace_setevent @id, @plan, 1, @on -- xml plan exec sp_trace_setevent @id, @plan, 5, @on -- xml plan / line exec sp_trace_setevent @id, @plan, 34, @on -- xml plan / objectname exec sp_trace_setevent @id, @plan, 51, @on -- xml plan / eventsequence end exec sp_trace_setevent @id, 45, 51, @on -- sp:stmtcompleted / eventseq exec sp_trace_setevent @id, 41, 51, @on -- sql:stmtcompleted / eventseq exec sp_trace_setevent @id, 166, 51, @on -- sql:stmtrecompile / eventseq exec sp_trace_setevent @id, 166, 21, @on -- sql:stmtrecompile / subclass exec sp_trace_setevent @id, 45, 1, @on -- sp:stmtcompleted / textdata exec sp_trace_setevent @id, 41, 1, @on -- sql:stmtcompleted / textdata exec sp_trace_setevent @id, 166, 1, @on -- sql:stmtrecompile / textdata exec sp_trace_setevent @id, 45, 13, @on -- sp:stmtcompleted / duration exec sp_trace_setevent @id, 41, 13, @on -- sql:stmtcompleted / durantion exec sp_trace_setevent @id, 45, 16, @on -- sp:stmtcompleted / reads exec sp_trace_setevent @id, 41, 16, @on -- sql:stmtcompleted / reads exec sp_trace_setevent @id, 45, 17, @on -- sp:stmtcompleted / writes exec sp_trace_setevent @id, 41, 17, @on -- sql:stmtcompleted / writes exec sp_trace_setevent @id, 45, 18, @on -- sp:stmtcompleted / cpu exec sp_trace_setevent @id, 41, 18, @on -- sql:stmtcompleted / cpu exec sp_trace_setevent @id, 45, 5, @on -- sp:stmtcompleted / line exec sp_trace_setevent @id, 41, 5, @on -- sql:stmtcompleted / line exec sp_trace_setevent @id, 45, 34, @on -- sp:stmtcompleted / objectname exec sp_trace_setevent @id, 45, 29, @on -- sp:stmtcompleted / nestlevel exec sp_trace_setfilter @id, 12, 0, 0, @spid -- spid = @@spid exec sp_trace_setfilter @id, 13, 0, 4, @minduration -- duration >= @min exec sp_trace_setfilter @id, 16, 0, 4, @minreads -- reads >= @minreads exec sp_trace_setfilter @id, 18, 0, 4, @mincpu -- cpu >= @mincpu if @rollback=1 begin tran exec sp_trace_setstatus @id, 1 exec (@batch) exec sp_trace_setstatus @id, 0 if @@trancount>0 rollback exec sp_trace_setstatus @id, 2 declare @results table ( eventclass smallint, subclass smallint, textdata nvarchar(4000), objectname varchar(128), nesting smallint, linenumber smallint, duration numeric(18,3), reads int, cpu int, writes int, compile int, rccpu int, rcduration bigint, xplan xml, id bigint primary key ) -- load trace select @file = @file+''.trc'' insert @results select eventclass, eventsubclass, textdata, objectname, nestlevel-2, linenumber, duration/1000.0, reads, cpu, writes, 0, null, null, '''', eventsequence from fn_trace_gettable ( @file , default ) where eventsequence is not null -- sequence query plans if @plan is not null update m set xplan = s.textdata from @results s cross apply( select top 1 * from @results where id > s.id and linenumber=s.linenumber and objectname=s.objectname order by id) m where s.eventclass = @plan -- sequence recompiles update m set compile = 1, subclass = s.subclass, rccpu = m.xplan.value(''*[1]/*[1]/*[1]/*[1]/*[1]/*[1]/@compilecpu'',''int''), rcduration = m.xplan.value(''*[1]/*[1]/*[1]/*[1]/*[1]/*[1]/@compiletime'',''int'') from @results s cross apply( select top 1 * from @results where id > s.id and textdata=s.textdata order by id) m where s.eventclass = 166 -- remove xplan variables update @results set xplan.modify(''delete *[1]/*[1]/*[1]/*[1]/*[1]/*[1]/@compiletime'') where xplan is not null update @results set xplan.modify(''delete *[1]/*[1]/*[1]/*[1]/*[1]/*[1]/@compilecpu'') where xplan is not null -- total measure select @total = nullif(max(case lower(@factor) when ''cpu'' then cpu when ''reads'' then reads when ''writes'' then writes else duration end),0), @rcduration = sum(rcduration), @rccpu = sum(rccpu), @rc = sum(case when eventclass=166 then 1 else 0 end) from @results update @results set rcduration = @rcduration, rccpu = @rccpu, compile = @rc where objectname=''sqltrace'' -- results select case when objectname=''sqltrace'' then '''' else isnull(cast(nullif(floor((@total/2+100*sum(case lower(@factor) when ''cpu'' then cpu+isnull(rccpu,0) when ''reads'' then reads when ''writes'' then writes else duration+isnull(rcduration,0) end))/@total),0) as varchar)+''%'','''') end as factor, case when textdata like ''exec%'' then ''\---- ''+textdata when textdata like ''%statman%'' then ''statistics -- ''+textdata else textdata end as text, case when objectname=''sqltrace'' or count(*)=1 then '''' else cast(count(*) as varchar) end as calls, case when objectname=''sqltrace'' then '''' else cast(nesting as varchar) end as nesting, case when objectname=''sqltrace'' then '''' else objectname+'' - ''+cast(linenumber as varchar) end [object - line], sum(duration) as duration, isnull(cast(nullif(sum(cpu),0) as varchar),'''') as cpu, isnull(cast(nullif(sum(reads),0) as varchar),'''') as reads, isnull(cast(nullif(sum(writes),0) as varchar),'''') as writes, isnull(cast(nullif(sum(compile),0) as varchar),'''') as compiles, case subclass when 1 then ''local'' when 2 then ''stats'' when 3 then ''dnr'' when 4 then ''set'' when 5 then ''temp'' when 6 then ''remote'' when 7 then ''browse'' when 8 then ''qn'' when 9 then ''mpi'' when 10 then ''cursor'' when 11 then ''manual'' else '''' end reason, case when sum(compile)>0 then isnull(cast(sum(rcduration) as varchar),''?'') else '''' end as rcduration, case when sum(compile)>0 then isnull(cast(sum(rccpu) as varchar),''?'') else '''' end as rccpu, cast(cast(xplan as nvarchar(4000)) as xml) xplan from @results where eventclass in (41,45) group by nesting, objectname, linenumber, textdata, eventclass, subclass, cast(xplan as nvarchar(4000)) order by min(case when @order='''' then id end), sum(case lower(@order) when ''cpu'' then cpu+isnull(rccpu,0) when ''reads'' then reads when ''writes'' then writes else duration+isnull(rcduration,0) end) desc goto ret help: exec sp__usage @proc,'' Scope show execution info about code passed into @batch Notes - originally from http://www.sommarskog.se/index.html Parameters @batch sql batch to analyse @minreads min reads (logical) @mincpu min cpu time (milliseconds) @minduration min duration (microseconds) @factor % (duration(default), reads, writes, cpu) @order order (duration, reads, writes, cpu) @plans include query plans - intentive (actual, estimated) @rollback run in a transaction and rollback @timeout set a maximum trace duration (seconds) Result Set ========== Name Description --------------- -------------------------------------------------------------------- Factor The total percent of the chosen measure taken by this statement. See the parameter @factor above. Blank if the percentage is 0. If the total of @factor is 0, Factor will be blank for all columns. Text The text of the statement Calls Number of times this statement was executed if more than 1. Nesting On which nesting level the statement was executed. Object - Line SQL module and line number for the statement. Duration Duration for the statement in milliseconds with three decimals. See also the section An Issue with Durations in (http://www.sommarskog.se/sqlutil/sqltrace.html) Reads Number of reads for the statement according to the trace. Blank when 0. Writes Number of writes for the statement according to the trace. Blank when 0. CPU CPU time for the statement in milliseconds. Blank when when 0. Compiles Number of recompiles for the statement if any. Reason Reason why the statement was recompiled. See the table below for the meaning of the codes. rcDuration Time spent on recompiling the statement. This value is derived from the execution plan, and thus only populated if you supply a value for @plans. The value is in milliseconds. The value for the batch itself – which has sqltrace as the object – has the total recompilation time for the batch. rcCPU CPU time for the recompilation of the statement. Like rcDuration, only populated if you included execution plans in the trace. XPlan The execution plan for the statement. Blank if you did not specify a value for @plans. Recompilation Reasons ===================== Code SubClassNo Description Local 1 Schema changed. Stats 2 Statistics changed. DNR 3 Deferred compile. SET 4 SET option changed. Temp 5 Temp table changed. Remote 6 Remote rowset changed. Browse 7 FOR BROWSE permissions changed. QN 8 Query notification environment changed. MPI 9 Partitioned view changed. Cursor 10 Cursor option changed. Manual 11 Option(RECOMPILE) or WITH RECOMPILE requested. '' ret: return @ret end -- sp__util_sqltrace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__profile_sql: -- =============================================================== sp__recompile select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__recompile',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090811 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__recompile') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__recompile') with nowait goto skip_sp__recompile end if @ver>090811 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__recompile') with nowait goto skip_sp__recompile end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__recompile') with nowait if exists( select top 1 null from sys.objects where name='sp__recompile' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__recompile] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090811\s.zaglio: removed apply of alter on #src'' v:090801\s.zaglio: exapanded to use #src and sp__script_alter v:090720\s.zaglio: replaced ##tmp... with #src for multi thread v:090705\s.zaglio: added drop of tmp table v:090623\s.zaglio: recompile a nested/connected object t:sp__recompile ''fn_mat_all'',@dbg=1 t:sp__recompile ''fn_mat_all'',@dbg=1,@svr=''gamon'',@db=''ramses'',@uid=''sa'',@pwd='''',@tofile=1 t: create table #src (lno int identity(10,10),line nvarchar(4000)) set nocount on insert into #src(line) select ''create table test_sp_recompile ('' insert into #src(line) select '' id int'' insert into #src(line) select '' )'' exec sp__recompile ''#src'',@dbg=1,@srv=''gamon'',@db=''ramses'',@uid=''sa'',@pwd='''',@tofile=1 select * from test_sp_recompile drop table test_sp_recompile drop table #src */ CREATE proc [dbo].[sp__recompile] @obj sysname=null, -- if #src use this (without alter) @srv sysname=null, @db sysname=null, @uid sysname=null, @pwd sysname=null, @tofile bit=0, @dbg bit=0 as begin set nocount on declare @r int, @t datetime, @msg nvarchar(4000), @sql nvarchar(4000), @sql1 nvarchar(4000), @sql2 nvarchar(4000), @sql3 nvarchar(4000), @line nvarchar(4000), @l int,@i int,@j int,@n int,@tmp sysname,@alter nvarchar(4000), @crlf nvarchar(2), @step smallint, @file sysname, @maxscp int select @r=0, @crlf=char(13)+char(10),@step=10,@tmp=''#src'', @sql='''',@sql1='''',@sql2='''',@sql3='''' if @obj is null goto help if @obj!=@tmp begin create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script @obj,@out=@tmp,@step=@step -- ,@dbg=@dbg -- calculate size of script exec sp__script_size @i out,@msize=@maxscp out,@go=0 -- because alter want the ''go'' if @i>@maxscp select @tofile=1 -- change create [...] with alter [...] exec sp__script_alter @alter=1,@step=@step,@dbg=0 end exec sp__script_reduce @normalize=8 -- remove while line on top and bottom if @tofile=1 begin set @file=''%temp%\tmp_''+replace(convert(nvarchar(48),newid()),''-'',''_'')+''.sql'' end -- load script and compile it if @tofile=0 exec sp__script_cache @sql out,@sql1 out,@sql2 out,@sql3 out,@go=0 else -- to file begin if @dbg=1 print ''output to file:''+coalesce(@file,''(null)'') exec sp__file_write @file out,@table=''#src'',@addcrlf=1,@dbg=@dbg end if @dbg=1 and @tofile=0 exec sp__script ''#src'' if @dbg=1 exec sp__elapsed @t out,''recompiling at:'' if @tofile=0 and @dbg=1 print ''(memory compiling)'' if @tofile=0 exec sp__script_run if @tofile=1 begin if @srv is null or @db is null or @uid is null or @pwd is null goto err_tofile declare @cmd nvarchar(4000) set @cmd=''osql -S''+@srv+'' -d''+@db+'' -U''+@uid+'' -P''+@pwd+'' -i''+@file+'' -n'' if @dbg=1 print @cmd create table #cmdout (lno int identity,line nvarchar(4000)) insert into #cmdout exec master..xp_cmdshell @cmd if @dbg=1 select * from #cmdout exec sp__drop @file -- sp__usage ''sp__select'' if exists(select * from #cmdout) begin select @r=1 select @msg=''#!''+coalesce(line,'''') from #cmdout where lno=1 select @msg=@msg+@crlf+coalesce(line,'''') from #cmdout where lno=2 select @msg=@msg+@crlf+coalesce(line,'''') from #cmdout where lno=3 select @msg=@msg+@crlf+coalesce(line,'''') from #cmdout where lno=4 if @msg=''#!'' select @msg=null,@r=0 end end -- to file if @dbg=1 exec sp__elapsed @t out,''compiled in ms:'' if @obj!=@tmp exec sp__drop @tmp goto ret err_nocreate: select @r=-1,@msg=''#!create keyword not found'' goto ret err_type: select @r=-2,@msg=''#!unk type'' goto ret err_con: select @r=-3,@msg=''#!no concurrency sp or error previous error'' goto ret err_src: select @r=-4,@msg=''#!source type not known'' goto ret err_tofile: select @r=-5,@msg=''#!login info mandatory'' goto ret help: select @msg =''parameters:\n'' +''\tcan be #src passed by caller formatted as "lno_line"\n'' +''\tcan be a name of a table formatted as "lno_line"\n'' +''\tcan be a file\n'' +''The format "lno_line" is lno int,line nvarchar(4000)\n'' exec sp__usage ''sp__recompile'',@extra=@msg select @msg=null ret: if not @msg is null exec sp__printf @msg return @r end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__recompile: -- =============================================================== sp__reg_write select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__reg_write',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__reg_write') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__reg_write') with nowait goto skip_sp__reg_write end if @ver>100919.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__reg_write') with nowait goto skip_sp__reg_write end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__reg_write') with nowait if exists( select top 1 null from sys.objects where name='sp__reg_write' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__reg_write] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919.1000\s.zaglio:write/delete a windows registry t: exec sp__reg_write ''hklm\software\sp__reg\test'',''wtest'',@dbg=1 exec sp__reg_write ''hklm\software\sp__reg\test1'',3,@dbg=1 exec sp__reg_write ''hklm\software\sp__reg\test2'',2.3,@dbg=1 exec sp__reg_write ''hklm\software\sp__reg\test'',null,@dbg=1 exec sp__reg_write ''hklm\software\sp__reg'',null,@dbg=1 exec sp__reg_write ''hklm\software\sp__reg\%'',null,@dbg=1 */ CREATE proc sp__reg_write @key nvarchar(512) = null, @val sql_variant = null out, @dbg int=0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=''sp__reg_write'', @ret=0 if @key is null goto help -- declarations create table #stdout (KeyExists int null) create table #values (val sysname null, data sql_variant null) declare @exists bit,@exists_parent bit, @k nvarchar(512),@v sysname,@t sysname, @r sysname,@vs nvarchar(4000),@vn int,@vb varbinary(4000) select @t=convert(sysname,sql_variant_property(@val,''BaseType'')) select @t=case @t when ''tinyint'' then ''reg_dword'' when ''int'' then ''reg_dword'' when ''smallint'' then ''reg_dword'' when ''bigint'' then ''reg_sz'' when ''nvarchar'' then ''reg_sz'' when ''varchar'' then ''reg_sz'' when ''varbinary'' then ''reg_binary'' when ''binary'' then ''reg_binary'' else ''reg_sz'' end if @t=''reg_sz'' select @vs=convert(nvarchar(4000),@val) if @t=''reg_dword'' select @vn=convert(int,@val) if @t=''reg_binary'' select @vb=convert(varbinary(4000),@val) -- initialization select @r=[root],@k=[key],@v=[value] from dbo.fn__reg_parse(@key) select @key=@k+''\''+@v -- ===================================================================== body == insert #stdout exec master..xp_regread @r,@k select top 1 @exists_parent=KeyExists from #stdout if @exists_parent=1 begin insert #values exec master..xp_regenumvalues @r,@k if @dbg=1 select * from #values select @exists=isnull((select top 1 1 from #values where val like @v),0) end else select @exists=0 if @dbg=1 exec sp__printf ''exists: "%s":%d; "%s":%d'',@key,@exists,@k,@exists_parent if @val is null begin if @dbg=1 exec sp__printf ''delete from %s val %s\%s or key %s'',@r,@k,@v,@key if @exists=1 and @v!=''%'' exec master..xp_regdeletevalue @r,@k,@v else begin if @v=''%'' and @exists_parent=1 exec master..xp_regdeletekey @r,@k else goto err_nokey end end else begin if @t=''reg_sz'' exec master..xp_regwrite @r,@k,@v,@t,@vs if @t=''reg_dword'' exec master..xp_regwrite @r,@k,@v,@t,@vn if @t=''reg_binary'' exec master..xp_regwrite @r,@k,@v,@t,@vb if @dbg=1 exec sp__printf ''write reg %s\\%s\%s of type "%s" with "%s"'',@r,@k,@v,@t,@val end goto ret -- =================================================================== errors == err_nokey: select @ret=1 goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope write/delete a registry of windows Parameters @key name of key with key_value; key_value can be % for delete of the key @val value (will be converted into string or int or bigint) if NULL, delete the key; if return NULL, the key do not exists return -1 for help, 0 if ok, 1 if key/val not exists Examples -- delete the key sp__reg_write ''''hklm\software\microsoft\windows nt\currentversion\aedebug\debugger'''',null -- read the key value and store it in @val. If @val is null the key do not exists sp__reg_read ''''hklm\software\microsoft\windows nt\currentversion\aedebug\debugger'''',@val out '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__reg_write' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__reg_write: -- ================================================================= sp__restore select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__restore',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131014.2300 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__restore') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__restore') with nowait goto skip_sp__restore end if @ver>131014.2300 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__restore') with nowait goto skip_sp__restore end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__restore') with nowait if exists( select top 1 null from sys.objects where name='sp__restore' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__restore] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131014.2300\s.zaglio: a small bug under mssql2k12 v:120726\s.zaglio: add run option and more info v:110325\s.zaglio: a modern version v:090808\S.Zaglio: added @replace v:081229\S.Zaglio: added @err out v:081227\S.Zaglio: added nounload,recovery options v:081130\S.Zaglio: added @rename to allow fast dublicate of db v:081125\S.Zaglio: added mssql2008 compatibility and corrected a bug v:081114\S.Zaglio: added comment and mssql2005 compatibility v:080509\S.Zaglio: added @simul v:080508\S.Zaglio: restore db from file replacing dst file name. Don''t manage multi filegroup. c:for more advanced versione see http://www.sqlservercentral.com/scripts/Backup+%2F+Restore/32003/ c:copy this on master db of dest server for first restore t:sp__restore ''db'',''device.bak'' t:sp__backup ''%temp%'',@opt=''doit'',@dbg=1 -- backup this db t:sp__restore ''test'',''C:\DOCUME~1\NETWOR~1\IMPOST~1\Temp\utility_110325_1251.bak'' */ CREATE proc [dbo].[sp__restore] @db sysname=null, @device nvarchar(1024)=null out, @opt sysname=null, @dbg int=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @db is null goto help if @db=db_name() goto err_db -- ============================================================== declaration == declare @mssqlver smallint,@dbid int,@crlf nvarchar(2),@doit bit, @sql nvarchar(4000),@tmp nvarchar(1024) -- ===================================================================== init == select @crlf=crlf, @doit=case when charindex(''|doit|'',@opt)>0 then 1 when charindex(''|run|'',@opt)>0 then 1 else 0 end from fn__sym() exec sp__get_temp_dir @tmp out select @device=replace(@device,''%temp%'',@tmp) if @dbg=1 exec sp__printf ''dev=%s, tmp=%s, db=%s, dt=%s'',@device, @tmp,@db /* to enable sp__restore to work on mssql2005/2008 EXECUTE sp_configure ''show advanced options'', 1 RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''xp_cmdshell'', ''1'' RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''Ole Automation Procedures'', ''1'' RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''SMO and DMO XPs'', ''1'' RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''show advanced options'', 0 RECONFIGURE WITH OVERRIDE */ if not exists( select [name] from master..sysdatabases where [name]=@db ) begin if @doit=1 exec(''create database [''+@db+'']'') else goto err_mdb end select @mssqlver=convert(smallint,substring(@@version,22,5)) if not @mssqlver in (2000,2005,2008,2012) goto err_ver -- drop database @name_db the dest db must not exist select @dbid=[dbid] from master.dbo.sysdatabases where [name]=@db if (select count(*) from master.dbo.sysaltfiles where [dbid]=@dbid )>2 goto err_max -- restore must replace original files with current files -- destination paths /* select @logical_name = null select @logical_name=rtrim(filename) from master.dbo.sysaltfiles where [dbid]=@dbid and fileid=1 select @file_path_data=reverse(@logical_name) select @i=charindex(''\'',@file_path_data) select @file_path_data=substring(@logical_name,1,len(@logical_name)-@i+1) select @logical_name=rtrim(filename) from master.dbo.sysaltfiles where dbid=@dbid and fileid=2 select @file_log=reverse(@logical_name) select @i=charindex(''\'',@file_log) select @file_log=substring(@logical_name,1,len(@logical_name)-@i+1) */ create table #Media ( LogicalName nvarchar(128) NULL, PhysicalName nvarchar(260) NULL, [Type] nchar(1) NULL, FileGroupName nvarchar(128) NULL, [Size] numeric(20,0) NULL, [MaxSize] numeric(20,0) NULL ) if @mssqlver>=2005 alter table #Media add FileID bigint NULL, CreateLSN numeric(25,0) NULL, DropLSN numeric(25,0) NULL, UniqueID uniqueidentifier NULL, ReadOnlyLSN numeric(25,0) NULL, ReadWriteLSN numeric(25,0) NULL, BackupSizeInBytes bigint NULL, SourceBlockSize int NULL, FileGroupID int NULL, LogGroupGUID uniqueidentifier NULL, DifferentialBaseLSN numeric(25,0) NULL, DifferentialBaseGUID uniqueidentifier NULL, IsReadOnly bit NULL, IsPresent bit NULL if @mssqlver>=2008 alter table #Media add TDEThumbprint varbinary(32) NULL; -- load info from backup file insert into #media exec(''RESTORE FILELISTONLY FROM DISK = ''''''+@device+'''''''') alter table #media add LocalName sysname, LocalPath nvarchar(1024) /* select case when saf.status=2 then ''D'' else ''L'' end as t,* from master.dbo.sysaltfiles saf where dbid=db_id(''utility'') */ update #media set LocalName=saf.name, LocalPath=saf.filename from #media m join master.dbo.sysaltfiles saf on saf.dbid=@dbid and m.type=case when saf.status=2 then ''D'' else ''L'' end if @@error!=0 goto ret if @dbg=1 select [Type],LogicalName,PhysicalName, LocalName,LocalPath from #media select @sql='' restore database [%db%] from disk = ''''%device%'''' with file=1, nounload,stats=10,replace ,recovery '' exec sp__str_replace @sql out,''%db%|%device%'',@db,@device select @sql=@sql+'' ,move ''''''+isnull(LogicalName,''?LogicalName?'') +'''''' to ''''''+isnull(LocalPath,''?LocalPath?'')+''''''''+@crlf from #media if @doit=1 begin exec(@sql) exec sp__prints ''-- xp_cmdshell ''''del "%s"'''''',@device end else exec sp__printsql @sql if @@error!=0 begin if @dbg=1 exec sp__printsql @sql select @ret=-2 goto ret end /* set @net_uid=coalesce(@net_uid,'''') set @net_pwd=coalesce(@net_pwd,'''') if @simul=0 print @sql else print '''' if @simul=0 begin exec(@sql) set @err=0 set @err=@@error if @err!=0 goto ret end else print ''*** SIMULATION *** (use @simul=0 to run really)'' if @net_uid<>'''' or @net_pwd<>'''' begin set @i=charindex(''\\'',@device) if @i<>0 set @i=@i+2 set @i=charindex(''\'',@device,@i) set @cmd=''net use ''+substring(@device,1,@i-1)+'' ''+@net_pwd+'' /user:''+@net_uid exec master..xp_cmdshell @cmd,no_output end -- se il db @name_db non esiste, allora esci dalla procedura */ goto ret -- =================================================================== errors == err_mdb: exec @ret=sp__err ''missing db; use CREATE DATABASE [%s]'',@proc,@p1=@db goto ret err_db: exec @ret=sp__err ''cannot restore on current db itself'',@proc goto ret err_ver: exec @ret=sp__err ''Tested only with MSSql 2K,2K5,2K8 (this is %d)'',@proc goto ret err_max: exec @ret=sp__err ''This procedure manage only db of 1 data file and 1 logical file'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope restore a db from a device. The Divice can be a remote file. (not yet implemented) If begin with \\, can add usr/pwd separated by |. Parameters @db the name of database to owerwrite @device the backup source if %temp%, uses the autogenerated temp file name @opt options run modern version of old "doit" doit execute instead of print code Examples sp__restore ''''testdb'''',''''%temp%\mybackup.bak'''' '' ret: return @ret end -- [sp__restore]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__restore: -- =================================================================== sp__ruler select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__ruler',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100917 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__ruler') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__ruler') with nowait goto skip_sp__ruler end if @ver>100917 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__ruler') with nowait goto skip_sp__ruler end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__ruler') with nowait if exists( select top 1 null from sys.objects where name='sp__ruler' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__ruler] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100917\s.zaglio: print a rules for text imports t:sp__ruler 120 */ create proc sp__ruler @len int=0, @start int=1 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=''sp__ruler'', @ret=0 if @len is null or @len<11 or @len>4000 goto help declare @r1 nvarchar(4000),@r2 nvarchar(4000) select @r1=''-- '',@r2=''-- '' while (@start<=@len) begin select @r2=@r2+case when @start%10=0 then ''.'' else convert(nchar(1),@start%10) end if @start%10=0 select @r1=@r1+right('' ''+convert(nvarchar(4),@start),10) select @start=@start+1 end -- while print @r1 print @r2 goto ret help: exec sp__usage @proc,'' Scope print a ruler of len @len for text imports Example -- 10 20 -- 12345678901234567890 '' select @ret=-1 ret: return @ret end -- sp__ruler' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__ruler: -- ================================================================= sp__run_cmd select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__run_cmd',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091127 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__run_cmd') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__run_cmd') with nowait goto skip_sp__run_cmd end if @ver>091127 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__run_cmd') with nowait goto skip_sp__run_cmd end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__run_cmd') with nowait if exists( select top 1 null from sys.objects where name='sp__run_cmd' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__run_cmd] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091127\s.zaglio: added @print and use of sp__print_table v:090925\s.zaglio: some tips v:090911\s.zaglio: added help v:090909\s.zaglio: added special replacement for %@@servername% and %db_name()% v:081119\S.Zaglio: added tmp_table existance test and create v:081118\S.Zaglio: extended with parameters and external(online)file support v:081016\S.Zaglio: extended @cmd to 4000 chars v:080926\S.Zaglio: added @dbg param v:080806\S.Zaglio: added set nocount v:080704\S.Zaglio: run external command appendig result to temp table (name returned if null) t:sp__run_cmd ''dir "c:\"'' t:sp__run_cmd ''dir %1'',''c:\'',@print=1 c:sample to run a command that need an external text file t:sp__run_cmd ''ftp -s:%file% 2>ftp_log.txt & type ftp_log.txt'',@file=''cmd1
cmd2'',@dbg=1 --> generate file and replae %file% with name c:sample to write a batch to a file also to a remote net server t:sp__run_cmd @batch,@file=''\\svr\dir\batch.cmd|net_uid|net_pwd'',@dbg=1 --> generate batch file t:sp__run_cmd ''echo hello world!'',@file=''c:\windows\temp\test.txt'',@dbg=1 --> generate batch file */ CREATE proc [dbo].[sp__run_cmd] @cmd varchar(4000)=null, @v1 sql_variant=null, -- replace %1 or will be added to @cmd @v2 sql_variant=null, -- replace %2 @v3 sql_variant=null, -- replace %3 @v4 sql_variant=null, -- replace %4 @v5 sql_variant=null, -- ... @v6 sql_variant=null, @v7 sql_variant=null, @v8 sql_variant=null, @v9 sql_variant=null, @file varchar(4000)=null, -- txt content or path|uid|pwd @nooutput bit=0, @tmp_table sysname=null output, @nodrop bit=0, @print bit=0, @dbg bit=0 as begin set nocount on if @dbg=1 exec sp__printf ''-- sp__run_cmd ------------------------------'' declare @proc sysname, @msg nvarchar(4000), @end_declare bit select @proc=''sp__run_cmd'' if @cmd is null goto help if not @v1 is null set @cmd=replace(@cmd,''%1'',convert(varchar(4000),@v1)) if not @v2 is null set @cmd=replace(@cmd,''%2'',convert(varchar(4000),@v2)) if not @v3 is null set @cmd=replace(@cmd,''%3'',convert(varchar(4000),@v3)) if not @v4 is null set @cmd=replace(@cmd,''%4'',convert(varchar(4000),@v4)) if not @v5 is null set @cmd=replace(@cmd,''%5'',convert(varchar(4000),@v5)) if not @v6 is null set @cmd=replace(@cmd,''%6'',convert(varchar(4000),@v6)) if not @v7 is null set @cmd=replace(@cmd,''%7'',convert(varchar(4000),@v7)) if not @v8 is null set @cmd=replace(@cmd,''%8'',convert(varchar(4000),@v8)) if not @v9 is null set @cmd=replace(@cmd,''%9'',convert(varchar(4000),@v9)) declare @sql varchar(4000) if @tmp_table is null begin set @tmp_table=''[dbo].[tmp_''+convert(varchar(64),newid())+'']'' set @sql=''create table ''+@tmp_table+'' (lno int identity, line nvarchar(4000))'' if @dbg=1 exec sp__printf @sql exec(@sql) end else begin if left(@tmp_table,1)=''#'' select @nodrop=1,@nooutput=1 if dbo.fn__exists(@tmp_table,''U'')=0 begin set @sql=''create table ''+@tmp_table+'' (lno int identity, line nvarchar(4000))'' if @dbg=1 exec sp__printf @sql exec(@sql) end end declare @crlf varchar(2) set @crlf=char(13)+char(10) declare @file_name varchar(1024) declare @uid sysname declare @pwd sysname declare @i int set @cmd=replace(@cmd,''%@@servername%'',@@servername) set @cmd=replace(@cmd,''%db_name()%'',db_name()) if charindex(''%file%'',@cmd)>0 begin exec sp__get_temp_dir @file_name out set @file_name=''"''+@file_name+''\''+convert(varchar(64),newid())+''.txt"'' set @cmd=replace(@cmd,''%file%'',@file_name) set @file=replace(@file,''
'',@crlf) if @dbg=1 exec sp__printf ''@file=%s @text=%s'',@file_name,@file exec sp__file_write @file_name,@text=@file,@dbg=@dbg end else begin if not @file is null begin set @file_name=dbo.fn__str_at(@file,''|'',1) set @uid =coalesce(dbo.fn__str_at(@file,''|'',2),'''') set @pwd =coalesce(dbo.fn__str_at(@file,''|'',3),'''') if @uid<>'''' or @pwd<>'''' begin set @i=charindex(''\\'',@file_name) if @i<>0 set @i=@i+2 set @i=charindex(''\'',@file_name,@i) set @sql=''net use ''+substring(@file_name,1,@i-1)+'' ''+@pwd+'' /user:''+@uid set @sql=''insert into ''+@tmp_table+'' exec master..xp_cmdshell ''''''+dbo.fn__inject(@sql)+'''''''' if @dbg=1 exec sp__printf @sql exec(@sql) end exec sp__file_write @file_name,@text=@cmd,@dbg=@dbg if @uid<>'''' or @pwd<>'''' begin set @sql=''net use ''+substring(@file_name,1,@i-1)+'' /delete'' set @sql=''insert into ''+@tmp_table+'' exec master..xp_cmdshell ''''''+dbo.fn__inject(@sql)+'''''''' if @dbg=1 exec sp__printf @sql exec(@sql) end goto ret end -- batch write form end -- if %file% set @sql=''insert into ''+@tmp_table+'' (line) values(''''''+dbo.fn__inject(@cmd)+'''''')'' if @dbg=1 exec sp__printf @sql exec(@sql) set @sql=''insert into ''+@tmp_table+'' exec master..xp_cmdshell ''''''+dbo.fn__inject(@cmd)+'''''''' if @dbg=1 exec sp__printf @sql exec (@sql) if not @file_name is null begin set @cmd=''del /q ''+@file_name set @sql=''insert into ''+@tmp_table+'' exec master..xp_cmdshell ''''''+dbo.fn__inject(@cmd)+'''''''' if @dbg=1 exec sp__printf @sql exec (@sql) end if @nooutput=0 begin if @print=0 begin select @sql=''select * from ''+@tmp_table+'' order by lno'' exec(@sql) end else exec sp__print_table @tmp_table end if @nodrop=0 begin set @sql=''drop table ''+@tmp_Table exec(@sql) end goto ret help: select @msg =''Use:\n'' +''\tsp__run_cmd ''''dir %1'''',''''c:\''''\n'' exec sp__usage @proc,@msg select @msg=null ret: end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__run_cmd: -- ================================================================= sp__run_dts select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__run_dts',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090121 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__run_dts') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__run_dts') with nowait goto skip_sp__run_dts end if @ver>090121 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__run_dts') with nowait goto skip_sp__run_dts end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__run_dts') with nowait if exists( select top 1 null from sys.objects where name='sp__run_dts' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__run_dts] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090121\S.Zaglio: changed name from sp__execute_DTS */ CREATE PROC sp__run_dts @PkgName nvarchar(255), -- Package Name (Defaults to most recent version) @param1 sysname=null, @value1 sysname=null, @Server nvarchar(255)=null, @ServerPWD nvarchar(255) = Null, -- Server Password if using SQL Security to load Package (UID is SUSER_NAME()) @IntSecurity bit = 0, -- 0 = SQL Server Security, 1 = Integrated Security @PkgPWD nvarchar(255) = '''' -- Package Password AS /* examples: -- for running SQL server security authorization spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa'' --/ or /-- spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa'', 0 -- for running SQL server security authorization spExecuteDTS ''127.0.0.1'', ''dtsImportData'', ''sa'', 1 */ SET NOCOUNT ON /* Return Values - 0 Successfull execution of Package - 1 OLE Error - 9 Failure of Package */ if @Server is null set @Server=@@servername DECLARE @hr int, @ret int, @oPKG int, @Cmd nvarchar(1000) -- Create a Pkg Object EXEC @hr = sp_OACreate ''DTS.Package'', @oPKG OUTPUT IF @hr <> 0 BEGIN PRINT ''*** Create Package object failed'' EXEC sp__displayoaerrorinfo @oPKG, @hr RETURN 1 END -- Evaluate Security and Build LoadFromSQLServer Statement IF @IntSecurity = 0 SET @Cmd = ''LoadFromSQLServer("'' + @Server +''", "'' + SUSER_SNAME() + ''", "'' + @ServerPWD + ''", 0, "'' + @PkgPWD + ''", , , "'' + @PkgName + ''")'' ELSE SET @Cmd = ''LoadFromSQLServer("'' + @Server +''", "", "", 256, "'' + @PkgPWD + ''", , , "'' + @PkgName + ''")'' EXEC @hr = sp_OAMethod @oPKG, @Cmd, NULL IF @hr <> 0 BEGIN PRINT ''*** LoadFromSQLServer failed'' EXEC sp__displayoaerrorinfo @oPKG , @hr RETURN 1 END -- set parameters if not @param1 is null begin EXEC @hr = sp_OAMethod @oPKG, ''AddGlobalVariable'', @Name = @param1, @Value = @value1 IF @hr <> 0 PRINT ''Cant Add Global Var'' end -- Execute Pkg EXEC @hr = sp_OAMethod @oPKG, ''Execute'' IF @hr <> 0 BEGIN PRINT ''*** Execute failed'' EXEC sp__displayoaerrorinfo @oPKG , @hr RETURN 1 END -- Check Pkg Errors EXEC @ret=sp__DisplayPkgErrors @oPKG -- Unitialize the Pkg EXEC @hr = sp_OAMethod @oPKG, ''UnInitialize'' IF @hr <> 0 BEGIN PRINT ''*** UnInitialize failed'' EXEC sp__displayoaerrorinfo @oPKG , @hr RETURN 1 END -- Clean Up EXEC @hr = sp_OADestroy @oPKG IF @hr <> 0 BEGIN EXEC sp__displayoaerrorinfo @oPKG , @hr RETURN 1 END RETURN @ret' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__run_dts: -- ================================================================= sp__run_sql select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__run_sql',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130605 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__run_sql') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__run_sql') with nowait goto skip_sp__run_sql end if @ver>130605 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__run_sql') with nowait goto skip_sp__run_sql end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__run_sql') with nowait if exists( select top 1 null from sys.objects where name='sp__run_sql' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__run_sql] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130605\s.zaglio: removed printf deprecated parameters v:091018\s.zaglio: NB: to remake&reduce using sp__loop v:090130\S.Zaglio: added a note about an error unmanaged v:090127\S.Zaglio: updated use of fn__servername v:090121\S.Zaglio: added @err_msg out v:081230\S.Zaglio: added @noexec to show only syntax v:081224\S.Zaglio: added quoted name management v:081223\S.Zaglio: added multilevel @dbg and corrected a bug on import of remote trace v:081218\S.Zaglio: replace @import_remote_trace with @trace_import v:081211\S.Zaglio: added @simul param to count rows will affected v:081209\S.Zaglio: corrected a bug on import of remote not ordered log v:081201\S.Zaglio: added @trace_proc for sp__trace v:081128\S.Zaglio: added relation of msg err to id with ref_id v:081126\S.Zaglio: complete rewrite of old one (now sp__run_sql_old) t: begin declare @r int,@rs bigint,@e int -- test simple local sql exec @r=sp__run_sql ''select top 3 * from sysobjects'',@rows=@rs out ,@err=@e out, @dbg=1 exec sp__printf ''@r=%d @rows=%d @err=%d'',@r,@rs,@e -- test error exec @r=sp__run_sql ''select tap 3 * from sysobjects'',@rows=@rs out ,@err=@e out, @dbg=1 exec sp__printf ''@r=%d @rows=%d @err=%d'',@r,@rs,@e -- test multiple server & db exec @r=sp__run_sql ''select top 3 *,rand(id) as ord from sysobjects order by ord'', @rows=@rs out ,@err=@e out, @svrs=''WSJ-VRT|SELFLINK|SELFLINK'', @dbs=''master|msdb|tempdb'', @trace=1,@dbg=1 exec sp__printf ''@r=%d @rows=%d @err=%d'',@r,@rs,@e end */ CREATE proc [dbo].[sp__run_sql] @sql nvarchar(4000)=null,-- use /*o:???*/ for obj replacement @v1 sql_variant=null, -- replacer for first %s or %d @v2 sql_variant=null, -- replacer for next %s or %d @v3 sql_variant=null, -- replacer for next %s or %d @v4 sql_variant=null, -- replacer for next %s or %d @svrs nvarchar(4000)=null, -- must be a linked server, can be multiple svr1|svr2 @dbs nvarchar(4000)=null, @rows bigint=null out, -- return inside/remote rowcount @err int=null out, @err_msg nvarchar(4000)=null out, @trace bit=0, @trace_import bit=1, @trace_proc sysname=null, @simul bit=0, @dbg smallint=0, @print bit=0, @noexec bit=0 as begin if @dbg<0 begin exec sp__printf ''@@nestlevel=%d'',@@nestlevel end set nocount on set @rows=null if @sql is null goto help -- initialization set @sql=replace(@sql,''"'','''''''') set @sql=dbo.fn__printf(@sql,@v1,@v2,@v3,@v4,null,null,null,null,null,null) if @svrs is null set @svrs=dbo.fn__servername(null) if @dbs is null set @dbs=db_name() -- check extensions declare @replacer sysname,@obj sysname if @sql like ''%/*%[%][%]%*/%'' or @sql like ''%/*%[_]%[%][%]%*/%'' begin -- t: sp__run ''print "/*sp_%*/"'' print ''replacer not implemented'' goto ret end declare @crlf nvarchar(2) set @crlf=char(13)+char(10) -- tracer declare @x1 int, @x2 int declare @tsql nvarchar(512) set @tsql='' if exists (select * from dbo.sysobjects where id = object_id(N''''[dbo].[log_trace]'''') ''+ ''and OBJECTPROPERTY(id, N''''IsUserTable'''') = 1) '' -- parameters declare @ok int set @ok=dbo.fn__ok() declare @r int declare @params sysname set @params=''@x1 int out,@x2 int out, @rows bigint out,@err int out, @r int out'' declare @returns sysname set @returns=''@x1=@x1 out,@x2=@x2 out,@rows=@rows out,@err=@err out,@r=@r out'' -- loops declare @svr sysname, @db sysname, @osql nvarchar(4000) declare @n_dbs int, @n_svrs int,@i int,@n int set @n_dbs=dbo.fn__str_count(@dbs,''|'') set @n_svrs=dbo.fn__str_count(@svrs,''|'') set @i=1 set @osql=@sql set @rows=0 set @err=null while (@i<=@n_svrs) begin set @sql=@osql set @svr=dbo.fn__str_at(@svrs,''|'',@i) if @n_dbs>1 set @db=dbo.fn__str_at(@dbs,''|'',@i) else set @db=@dbs set @i=@i+1 if dbo.fn__servername(@svr)=@svr set @svr='''' if @db=db_name() set @db='''' if @svr<>'''' set @svr=dbo.fn__sql_quotename(@svr) if @db<>'''' set @db=dbo.fn__sql_quotename(@db) if not @replacer is null set @sql=replace(@sql,@replacer,@obj) if @trace=0 and @svr='''' and @db<>'''' set @sql=''use ''+@db+ '' ''+@sql if @svr<>'''' or @db<>'''' begin if @simul=1 set @sql=''begin transaction ''+@sql set @sql=@sql+'' select @err=@@error,@rows=@@rowcount '' if @simul=1 set @sql=@sql+''rollback transaction '' end -- read log_trace from other db of local server if @trace=1 and @trace_import=1 and @db<>'''' begin set @sql='' use ''+@db+'' ''+@tsql+'' select @x1=coalesce(max(id),0)+1 from dbo.log_trace ''+@sql+ '' ''+@tsql+'' select @x2=coalesce(max(id),0) from dbo.log_trace '' end if @svr<>'''' and @db<>'''' set @sql=''exec ''+@svr+''.''+@db+''.dbo.sp_executesql N''+dbo.fn__sql_quote(@sql)+ '',N''+dbo.fn__sql_quote(@params)+'',''+@returns set @x1=null set @x2=null set @r=null if @svr<>'''' or @db<>'''' begin declare @m_rows bigint set @m_rows=null declare @m_err int set @m_err=null -- if @dbg>=@@nestlevel print ''begin declare @x1 int,@x2 int,@rows bigint,@err int,@r int ''+@sql+'' print @err print @rows end'' if abs(@dbg)>=@@nestlevel and @n_svrs>1 select ''====== query server separator for ''+@svr+''.''+@db+'':''+ @osql+'' ----------------------'' if @print=1 or @noexec=1 print @sql if @noexec=0 exec sp_executesql @sql,@params,@x1=@x1 out,@x2=@x2 out,@rows=@m_rows out,@err=@m_err out,@r=@r out set @rows=@rows+@m_rows if coalesce(@err,0)=0 set @err=@m_err end else begin if @print=1 or @noexec=1 print @sql if @noexec=0 exec(@sql) select @err=@@error,@rows=@rows+@@rowcount end declare @trc_id int if @trace=1 exec sp__trace @sql,@last_id=@trc_id out, @proc=@trace_proc,@dbg=@dbg -- manage and trace error set @err_msg='''' if @err<>0 and @noexec=0 begin /* n.b.: in some situation this sp cause another error (maybe into stack) and leave without manage the error -- this will solve the above problem but for now don''t work create table #dbccout (id int identity,col1 nchar(77)) insert into #dbccout exec (''dbcc outputbuffer(@@spid)'') select @i=min(id),@n=max(id) from #dbccout while (@i<=@n) begin select @err_msg = @err_msg + substring(col1, 62 + 1, 1) + substring(col1, 62 + 3, 1) + substring(col1, 62 + 5, 1) + substring(col1, 62 + 7, 1) + substring(col1, 62 + 9, 1) + substring(col1, 62 + 11, 1) + substring(col1, 62 + 13, 1) + substring(col1, 62 + 15, 1) from #dbccout where id=@i and left(col1, 8) <> replicate(''0'', 8) order by col1 set @i=@i+1 end -- while drop table #dbccout -- exec sp__outputbuffer @err_msg out */ if @svr is null begin -- if sql on server declare @lcid smallint select @lcid=lcid from master..syslanguages where langid=@@langid declare @msgerr sysname select @msgerr=description from master..sysmessages where error=@err and msglangid=@lcid if difference(@err_msg,@msgerr)<3 set @err_msg=@msgerr end if @svr is null set @err_msg=dbo.fn__printf(''#!(%d):%s'',@err,@err_msg,null,null,null,null,null,null,null,null) else set @err_msg=dbo.fn__printf(''#!(%d) on %s:%s'',@err,@svr,@err_msg,null,null,null,null,null,null,null) -- select top 1 @msg=description from master.dbo.sysmessages where error=@err if left(ltrim(@sql),7) in (''select '',''insert '',''delete '',''update '',''execute'',''exec @r'',''execute'') set @sql=dbo.fn__str_simplify(@sql,default) set @err_msg=@err_msg+'' (''+left(@sql,4000-len(@err_msg))+'')'' if @trace=1 exec sp__trace @err_msg,@ref_id=@trc_id , @proc=@trace_proc else exec sp__printf @err_msg end -- if @err if (@svr<>'''' or @db<>'''') and @trace=1 and @trace_import=1 and not @x1 is null and not @x2 is null begin -- import remota trace log if @svr<>'''' and @db<>'''' set @sql=''insert into log_trace(spid,txt,ref_id) ''+ ''select top 100 percent * from openquery(%svr%,"''+ ''select spid,txt,ref_id from %db%.dbo.log_trace ''+ ''where id between %x1% and %x2% order by id")'' if @svr= '''' and @db<>'''' set @sql=''insert into log_trace(spid,txt,ref_id) ''+ ''select top 100 percent spid,txt,ref_id from %db%.dbo.log_trace ''+ ''where id between %x1% and %x2% order by id'' exec sp__str_replace @sql out,''"|%svr%|%db%|%x1%|%x2%'','''''''',@svr,@db,@x1,@x2 if @dbg>=@@nestlevel print @sql exec(@sql) end -- import remote trace end -- while svrs goto ret help: exec sp__usage ''sp__run_sql'' ret: return coalesce(@r,@err,@ok) end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__run_sql: -- ================================================================= sp__run_vbs select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__run_vbs',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100919 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__run_vbs') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__run_vbs') with nowait goto skip_sp__run_vbs end if @ver>100919 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__run_vbs') with nowait goto skip_sp__run_vbs end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__run_vbs') with nowait if exists( select top 1 null from sys.objects where name='sp__run_vbs' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__run_vbs] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100919\s.zaglio: adapted to sp__err and other conventions v:100127\s.zaglio: added err return v:100104\s.zaglio: run a vbs c:originally from http://www.sql.ru/forum/actualthread.aspx?bid=1&tid=210409&hl t: declare @vbs nvarchar(4000),@out nvarchar(4000) select @vbs='' function main() hello="hello world" ''''print hello not allowed main=hello end function'' exec sp__run_vbs @vbs,@out out print @out select @vbs='' option explicit sub main() dim hello hello="hello" end sub'' exec sp__run_vbs @vbs,@out out print @out */ CREATE proc [dbo].[sp__run_vbs] @vbs nvarchar(4000)=null, @out nvarchar(4000)=null out, @start sysname=null, @dbg bit=0 as begin set nocount on; declare @proc sysname,@i int,@j int,@ret int declare @hr int, @obj int,@msg nvarchar(4000), @cmd sysname select @proc=''sp__run_vbs'',@out=null,@ret=0 if @vbs is null goto help if @start is null begin select @i=charindex(''function '',@vbs) select @j=charindex(''('',@vbs,@i) if @i>0 and @j>0 select @start=ltrim(rtrim(substring(@vbs,@i+9,@j-@i-9))) else begin select @i=charindex(''sub '',@vbs) select @j=charindex(''('',@vbs,@i) if @i>0 and @j>0 select @start=ltrim(rtrim(substring(@vbs,@i+4,@j-@i-4))) end end if @start is null goto err_start if @dbg=1 exec sp__printf ''func:%s\ncode:\n%s'',@start,@vbs select @cmd=''scriptcontrol'' execute @hr = sp_oacreate @cmd, @obj out; if @hr!=0 goto err select @cmd=''language'' execute @hr = sp_oasetproperty @obj, @cmd, ''vbscript''; if @hr!=0 goto err select @cmd=''addcode'' execute @hr = sp_oamethod @obj, @cmd, null, @vbs; if @hr!=0 goto err select @cmd=''run'' execute @hr = sp_oamethod @obj, @cmd, @out out, @start if @hr!=0 goto err if @dbg=1 exec sp__printf ''out:%s'',@out goto ret err: select @ret=@hr declare @source varchar(255), @description varchar(255) exec @hr = sp_oageterrorinfo @obj, @source out, @description out exec @ret=sp__err ''cmd:%s; src:%s; des:%s; @out:%s'',@proc, @p1=@cmd,@p2=@source,@p3=@description,@p4=@out goto ret err_start: exec @ret=sp__err ''starting function/sub not found or specified'',@proc goto ret help: select @ret=-1 exec sp__usage @proc,''Parameters: @start name of starting function or automatic '' ret: if @obj!=0 exec sp_oadestroy @obj return @ret end -- [sp__run_vbs]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__run_vbs: -- ================================================================== sp__script select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=171214 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script') with nowait goto skip_sp__script end if @ver>171214 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script') with nowait goto skip_sp__script end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script') with nowait if exists( select top 1 null from sys.objects where name='sp__script' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script d:111027.1000\s.zaglio:sp__scropt v:171214\s.zaglio:added %license%(@license_tag) in #vars v:131107\s.zaglio:corrected a no output when scripting by 0xID v:131030\s.zaglio:reenabled script of comments in case of table or view v:130729.1001\s.zaglio:managed #objs v:130729,130723,130719,130718,130712,130710\s.zaglio:arranging templates r:130708,130701\s.zaglio:some deprecation, some innovation;moving code from sp__script_group v:130506,130403\s.zaglio:added test of same ver, diff user;changed ovrchk behaviour v:130325,121218\s.zaglio:removed extra warning;again around problem of \\ v:121212.1800\s.zaglio:semi-solved problem of "\" v:121108.1621\s.zaglio:reintroduced bug 111027 to understand where happen (see comm) v:121012\s.zaglio:now pass @opt to sp__script_code v:120731.1800\s.zaglio:ix->pk and remote sp__script v:120730.1700\s.zaglio:adding help for #src_def v:120717.1656\s.zaglio:adding opt OVRCHK v:120622\s.zaglio:added usage of related option v:120213,111028\s.zaglio:about obj as hex id;moved trigger scripting here v:111027\s.zaglio:solved problem with lines that end with \ that escape the return v:110629,110628\s.zaglio:a small bug on drop;added scripting of trigger on db v:110627,110614\s.zaglio:adapted to new hex codes;added encapsulation on drop v:110531,110510\s.zaglio:a small bug near help;removed external help v:110329\s.zaglio:removed @out (use ..tofile) and html opt and added number v:100919.1000\s.zaglio: a bug near scripting of obj of other db v:100919,100912\s.zaglio: added drop of constraint;resolved tremendous bug of print '''' v:100724,100718\s.zaglio: more dbg info;added go separator on multi obj v:100515,100509\s.zaglio: a minimal chk on obj existance;bug opt not passed to sp__script_table v:100418.2200\s.zaglio:added reverse option fro remote svr call v:100411,100405\s.zaglio:added synonym;adapted for sp__Script_group added go before raiserror v:100404,100403\s.zaglio:divided into more sps;added replacements and out to dir/file r:100328\s.zaglio:third remake of scripting utility t:sp__script ''sp__script'',@as=''sp__scropnt'',@dbg=1 t:sp__script ''sp__script'',@opt=''select'',@dbg=1 t:sp__script ''log_ddl'',@opt=''drop'' t:sp__script ''sp__script'',@opt=''upgrade'',@dbg=1 */ CREATE proc [dbo].[sp__script] @obj sysname=null, -- single obj @as sysname=null, @license sysname=null, @opt sysname=null, -- see help @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid), @ret=0, @opt=dbo.fn__str_quote(coalesce(@opt,''''),''|'') if @obj is null goto help -- ================================================================== declare == declare @type nvarchar(2), @drop nvarchar(4000), @i int, @n int,@sql nvarchar(4000), @db sysname,@sch sysname,@sch_id int, @lno_begin int,@lno_end int, @psep nchar(1), @pos int,@src_id int,@src_pos int, @crlf nvarchar(2), @tofile int,@vars_id int, @def bit,@upgrade bit, @nohdr bit,@nodecl bit,@nofot bit, @noprop bit,@notrg bit, @ver sysname,@aut sysname, @tgs sysname,@var_id int, @license_tag nvarchar(32) -- ===================================================================== init == select @tgs=''rv'', @license_tag=''%license%'', @def=isnull(object_id(''tempdb..#src_def''),0), @psep=psep, @crlf=crlf, @upgrade=charindex(''|upgrade|'',@opt), @nohdr=charindex(''|nohdr|'',@opt), @nofot=charindex(''|nofot|'',@opt), @nodecl=charindex(''|nodecl|'',@opt), @tofile=charindex(''|tofile|'',@opt), @noprop=charindex(''|noprop|'',@opt), @notrg=charindex(''|notrg|'',@opt), @src_id=object_id(''tempdb..#src''), @var_id=object_id(''tempdb..#vars'') from dbo.fn__sym() if @src_id is null create table #src (lno int identity primary key,line nvarchar(4000)) if @upgrade=1 create table #out (lno int primary key,line nvarchar(4000)) -- for speed optimization, #tpl can be passed prefilled from sp__script_group if object_id(''tempdb..#tpl'') is null begin create table #tpl (lno int identity,line nvarchar(4000)) --create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) create table #tpl_cpl(tpl binary(20),section sysname,y1 int,y2 int) end -- init templates if @upgrade=1 begin exec @ret=sp__script_templates ''script'' if @ret!=0 goto ret end -- ===================================================================== body == if left(@obj,2)=''0x'' -- script directly from log_ddl begin exec sp__script_code @obj,@opt=@opt,@dbg=@dbg goto output end -- special case for temp objs if left(@obj,1)=''#'' begin exec @ret=sp__script_code @obj goto ret end select @db =db, @sch=sch, @obj=obj from dbo.fn__parsename(@obj,0,1) if @db!=db_name() begin -- roaming script to remote sp__script select @sql=''use ''+quotename(@db)+'' '' +''exec @ret=sp__script ''''''+@obj+'''''','' +''@opt=''''''+@opt+'''''','' +''@dbg=''+convert(sysname,@dbg) exec sp_executesql @sql,N''@ret int out'',@ret=@ret out if @@error!=0 goto err_rmt goto ret end -- get local object info select @sch_id=schema_id(@sch) if @nohdr=0 -- 171214\s.zaglio -- and @upgrade=1 begin /* sp__Script ''sp__script'',@opt=''upgrade'',@license=''test'' only %license% can be replaced by @licence, because scripted code can contain tokens of itself */ if not @var_id is null select @obj=case when id=''%obj%'' then cast(value as sysname) else @obj end, @ver=case when id=''%ver%'' then cast(value as sysname) else @ver end, @aut=case when id=''%aut%'' then cast(value as sysname) else @aut end, @drop=case when id=''%drop%'' then cast(value as nvarchar(512)) else @drop end, @license=case when id=@license_tag then cast(value as sysname) else @license end from #vars where id in (''%obj%'',''%ver%'',''%aut%'',''%drop%'',''%license%'') else begin select @type=typ, @drop=if_exists+@crlf+'' ''+drop_script from fn__sysobjects(@obj,@sch_id,''drop_script|if_exists'') select @ver=cast(cast(val1 as decimal(10,4)) as sysname), @aut=val2 from fn__script_info(@obj,@tgs,0) end end if @type is null select @type=typ from fn__sysobjects(@obj,@sch_id,default) if @def=1 begin select @src_pos=isnull(max(lno),ident_seed(''#src''))--+ident_incr(''#src'') from #src insert #src_def(xtype,cod,idx,flags) select @type,@obj,@src_pos,0 end -- ============================================================ script object == if @type is null goto err_typ if @dbg=1 exec sp__printf ''-- db:%s, obj:%s, xt:%s'',@db,@obj,@type if @upgrade=1 begin if @nodecl=0 exec @ret=sp__script_template ''%declarations%'' if @nohdr=0 exec @ret=sp__script_template @section=''%obj_ver_chk%'', @tokens=''%obj%|%drop%|%ver%|%aut%'', @v1=@obj,@v2=@drop,@v3=@ver,@v4=@aut if @ret!=0 goto ret -- if not catched by caller end -- upgrade -- mark last row before the insert of new code select @lno_begin=isnull(max(lno),0) from #src -- real script generation is demanded to sub proc if @type in (''U'',''S'') exec sp__script_table @obj=@obj,@opt=@opt,@dbg=@dbg else begin -- sp__script_code ''sp__Script'' if @type in (''P'',''TR'',''FN'',''TF'',''IF'',''V'',''SN'',''TD'') exec sp__script_code @obj=@obj,@opt=@opt,@dbg=@dbg else goto err_typ end -- sp__comment ''sp__script'',''script an object'' -- fist script line of code select @lno_begin=( select top 1 lno from #src where lno>@lno_begin order by lno ) -- last script line select @lno_end=max(lno) from #src if @dbg=1 exec sp__printf ''-- begin:%d, end:%d'',@lno_begin,@lno_end -- script properties if (@upgrade=1 and @noprop=0 and left(@obj,1)!=''#'') or @type in (''U'',''V'') exec sp__script_prop @obj=@obj,@dbg=@dbg -- rename if not @as is null update #src set line=replace(line, dbo.fn__sql_unquotename(ltrim(rtrim(@obj))), dbo.fn__sql_unquotename(ltrim(rtrim(@as))) ) where lno between @lno_begin and @lno_end -- apply vars if not @license is null begin update #src set line=replace(line,@license_tag,@license) where charindex(''l:''+@license_tag,line)>0 end if @upgrade=1 begin /* 121108\s.zaglio: the \ at end of line, means:"continue on next line" and give compile problem so I add a \\crlfcrlf as in this example print ''[1] foo\\ bar'' print ''[2] foo\\\ bar'' print ''[3] foo\\\ bar'' [1] foo bar [2] foo\ bar [3] foo\\ bar */ update #src set line=case when right(line,1)=''\'' then line+''\''+@crlf+ -- 121218\s.zaglio case @tofile when 0 then @crlf -- out to console else '''' -- out to file end else line end where lno between @lno_begin and @lno_end update #src set line=replace(line,'''''''','''''''''''') where lno between @lno_begin and @lno_end update #src set line=''exec dbo.sp_executesql @statement = N'''''' +line where lno=@lno_begin update #src set line=line+'''''''' where lno=@lno_end end -- quote -- script triggers for table if @type in (''U'') and @notrg=0 begin declare @trg sysname declare @tr_opt sysname select @tr_opt=@opt+''related'' declare cs cursor local for select [name] from sysobjects o where parent_obj=object_id(@obj) and xtype=''TR'' -- ?? ctype=''TR'' ?? maybe in the future open cs while 1=1 begin fetch next from cs into @trg if @@fetch_status!=0 break insert #src(line) select '''' if @def=1 begin select @src_pos=isnull(max(lno),ident_seed(''#src''))--+ident_incr(''#src'') from #src insert #src_def(xtype,cod,idx,flags) select ''TR'',@trg,@src_pos,0 end if @db=db_name() exec sp__script_code @trg,@opt=@tr_opt,@dbg=@dbg else begin select @sql =''use [''+@db+''] exec sp__script_code @obj='''''' +@trg+'''''',@opt=''''''+@tr_opt+'''''',@dbg=''+convert(sysname,@dbg) exec(@sql) if @@error!=0 goto err_rmt end end -- while of cursor close cs deallocate cs end -- triggers if @upgrade=1 and @nofot=0 begin exec @ret=sp__script_template @section=''%skip_obj%'', @tokens=''%obj%'', @v1=@obj if @ret!=0 goto ret end -- upgrade -- ============================================================ output result == output: if charindex(''|print|'',@opt)!=0 or @src_id is null exec sp__print_table ''#src'' if charindex(''|select|'',@opt)!=0 select line from #src order by lno goto ret -- =================================================================== errors == err_onf: exec @ret=sp__err ''object "%s" not found'',@proc,@p1=@obj goto ret err_typ: exec @ret=sp__err ''unknow type or object for "%s"'',@proc,@p1=@obj goto ret err_rmt: exec @ret=sp__err ''missing or wrong script utility on %s'',@proc,@p1=@db goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope script any object (or try to do that) Parameters @obj name of object to script id of release (see sp__script_history) @as rename object (very simple replace;do not work always) @opt options (and see options below sub sp) upgrade wrap code for upgrade (sp__script_group) nodecl leave out the upgrade''''s local variable declaration nohdr leave out the upgrade''''s header nofot leave out the upgrade''''s footer tofile necessary because different behaviour of ending \\ noprop do not script extended property print force print as text select show result as select Notes * can be called from sp__script_group * call sp__script_code if @obj is an proc,func,view,synonim,trigger * call sp__script_table if @obj is a table * if table #src_def is defined (called by sp__script_align), fill it with definition info of sub objects create table #src_def( xtype varchar(2), -- sysobjects.xtype id int identity, -- parent id rid int, -- property parent id flags smallint, -- flags depend on xtype (see below) cod sysname, -- object or property name val sql_variant, -- value of property idx int -- relative source position start ) xtype&description (* = managed) flags =========================================== ============================ AF = Aggregate function (CLR) C = CHECK constraint D = Default or DEFAULT constraint F = FOREIGN KEY constraint L = Log FN =*Scalar function FS = Assembly (CLR) scalar-function FT = Assembly (CLR) table-valued function IF =*In-lined table-function IT = Internal table IX =*Index PK =*PrimayKey UQ =*vincolo UNIQUE (il tipo è K) P =*Stored procedure PC = Assembly (CLR) stored-procedure RF = Replication filter stored procedure S = System table SN =*Synonym SQ = Service queue TA = Assembly (CLR) DML trigger TF =*Table function TR =*SQL DML Trigger TD =*trigger database TT = Table type U =*User table V =*View X = Extended stored procedure --= comments '' -- show other helps exec sp__script_code exec sp__printf '''' exec sp__script_table ret: return @ret end -- sp__script' exec sp__comment '[sp__script]','script an object' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script: -- ============================================================== sp__script_act select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_act',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130116 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_act') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_act') with nowait goto skip_sp__script_act end if @ver>130116 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_act') with nowait goto skip_sp__script_act end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_act') with nowait if exists( select top 1 null from sys.objects where name='sp__script_act' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_act] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:action,trigger,db,store,application,personalization v:130116\s.zaglio: +quotename(@db) v:121003\s.zaglio: follow synonym v:120907\s.zaglio: connect application scripts to db trigger */ CREATE proc sp__script_act @sp sysname = null, @obj sysname = null, @cmd nvarchar(4000) = null, @idx int = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare @hash_sp int,@hash_obj int, @db sysname,@sql nvarchar(4000), @end_declare bit -- =========================================================== initialization == select @db=db_name(), @sp=upper(@sp), -- for compatibility with sp__script_store @obj=upper(@obj), -- for compatibility with sp__script_store @hash_sp=dbo.fn__crc32(@sp), @hash_obj=dbo.fn__crc32(parsename(@obj,1)), @end_declare=1 -- ======================================================== second params chk == if '''' in (isnull(@sp,''''),isnull(@obj,''''),isnull(@cmd,'''')) -- or@opt=''||'' goto help -- follow synonym exec sp__script_synonym @obj out,@obj,@opt=''path'' if isnull(parsename(@obj,3),@db)!=@db begin select @sp=quotename(@db)+''.''+isnull(parsename(@sp,2),'''')+''.''+parsename(@sp,1), @sql=N''exec @ret=''+quotename(parsename(@obj,3)) +''..sp__script_act @sp,@obj,@cmd'' exec sp_executesql @sql, N''@sp sysname,@obj sysname,@cmd nvarchar(4000),@ret int out'', @sp=@sp,@obj=@obj,@cmd=@cmd,@ret=@ret out goto ret end if object_id(@sp) is null or object_id(@obj) is null goto err_unk -- ===================================================================== body == update script_act set txt=@cmd, idx=@idx where rid=@hash_sp and pid=@hash_obj if @@rowcount=0 begin insert script_act(rid,pid,idx,txt) select @hash_sp,@hash_obj,@idx,@cmd end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_unk: select @e_msg=''not found "%s" or "%s"'',@e_p1=@sp,@e_p2=@obj goto err -- ===================================================================== help == help: exec sp__usage @proc,'' Scope connect create/drop/alter of an object to local application code Notes data is stored into table "script_act" Parameters @sp is the name of storec procedure that register the dynamic code and with @obj is used a primary key @obj name of object to connect @cmd sql code to execute @opt options (not used) Examples exec sp__script_act @proc,@tbl,@cmd -- list of application triggers -- '' select (select name from sys.objects where dbo.fn__crc32(upper(name))=s.rid) sp, (select name from sys.objects where dbo.fn__crc32(upper(name))=s.pid) obj, s.txt as sql into #tmp from script_act s exec sp__select_astext ''select * from #tmp'',@header=1 drop table #tmp select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_act' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_act: -- ============================================================ sp__script_alias select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_alias',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_alias') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_alias') with nowait goto skip_sp__script_alias end if @ver>121018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_alias') with nowait goto skip_sp__script_alias end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_alias') with nowait if exists( select top 1 null from sys.objects where name='sp__script_alias' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_alias] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:script,utility v:121018\s.zaglio: a bug near @opt v:120528\s.zaglio: renamed #objs in #alias_objs to avoid conflict v:120523\s.zaglio: a non correct err msg when target is a synonym v:120521\s.zaglio: a bug near dynamic sql v:120516\s.zaglio: adapted to new fn__script_sysobjs v:120504.1446\s.zaglio: added uses of synonyms v:111205\s.zaglio: added show of source when error occur in compilation v:110415\s.zaglio: added more table exclusions v:110213\s.zaglio: added more help for debug v:101113\s.zaglio: added support of excludes with % v:100724\s.zaglio: a bug around bits v:100722\s.zaglio: test destination to overrides/create correctly;+@excludes v:100721\s.zaglio: excluded sp_info,help v:100720\s.zaglio: generate a caller of objects of other db t:sp_config ''web%'' */ CREATE proc [dbo].[sp__script_alias] @db sysname = null, @like sysname = null, @excludes nvarchar(4000) = null, @opt sysname = null, @dbg int = 0 as begin set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @like is null select @like=''%'' if @db is null goto help if @db=db_name() goto err_nodb -- drop table #alias_objs create table #alias_objs( id int identity,obj sysname,xtype sysname, flds nvarchar(4000),types nvarchar(4000), nulls nvarchar(4000) null, outs nvarchar(4000) null ) create table #excludes (obj sysname) insert #excludes select ''sp_info'' insert #excludes select ''sp_find'' insert #excludes select ''help'' insert #excludes select ''hashbytes'' insert #excludes select cod from fn__script_sysobjs((select obj from tids)) insert #excludes select token from dbo.fn__str_params(@excludes,'','',default) -- expand wild tokens insert #excludes select o.name from #excludes e join sysobjects o on o.name like e.obj where e.obj like ''%[%]%'' delete from #excludes where obj like ''%[%]%'' declare @sql nvarchar(4000), @h1 sysname,@h2 sysname,@h3 sysname,@h4 sysname -- select * from fn__script_sysobjs((select obj from tids)) select @h1=''/* leave this'', @h2='' g:sp__script_alias'', @h3='' v:''+convert(sysname,getdate(),12)+''\generated by ''+@proc, @h4=''*/'', @sql='' insert #alias_objs (obj,xtype,flds,types) select o.name, o.xtype, ''+quotename(@db)+''.dbo.fn__flds_of(o.name,'''','''',null) flds, ''+quotename(@db)+''.dbo.fn__flds_type_of(o.name,''''|'''',null) types from ''+quotename(@db)+''..sysobjects o -- excludes extension/support system object tables left join fn__script_sysobjs((select obj from tids)) so on right(o.name,len(so.cod)+1)=''''_''''+so.cod where xtype in (''''tf'''',''''if'''',''''fn'''',''''p'''') and name like ''''''+@like+'''''' and not name like ''''%[_][_]%'''' -- not the utilities and not name like ''''dt[_]%'''' -- not the mssql dt tables and not name like ''''tbl[_]%'''' -- not the utility tables and not name like ''''bak[_]%'''' -- not the backup tables and not name like ''''%bak'''' -- not the backup tables and not name like ''''tmp%'''' -- not the temp table and not name like ''''[_]%'''' -- not the temp table and not name like ''''0%'''' -- not the temp table and not name in(select obj from #excludes) -- special local sp related to sp__info order by xtype,name -- select * from #alias_objs -- select * from #excludes declare @i int,@n int,@name sysname,@xt nvarchar(4), @nulls nvarchar(4000),@outs nvarchar(4000) select @i=min(id),@n=max(id) from #alias_objs while (@i<=@n) begin select @name=''''''+quotename(@db)+''..''''+obj,@xt=xtype from #alias_objs where id=@i if @xt=''''P'''' begin select @nulls=null,@outs=null select @nulls=isnull(@nulls+'''','''','''''''')+convert(nchar(1),isnullable) from ''+quotename(@db)+''..syscolumns where id=object_id(@name) order by number,colorder select @outs =isnull(@outs+'''','''','''''''')+convert(nchar(1),isoutparam) from ''+quotename(@db)+''..syscolumns where id=object_id(@name) order by number,colorder update #alias_objs set nulls=@nulls, outs=@outs where id=@i end select @i=@i+1 end -- while '' if @dbg=1 exec sp__printf ''%s'',@sql exec sp_executesql @sql if @dbg=1 exec sp__select_astext ''select * from #alias_objs order by id'' create table #src(lno int identity,line nvarchar(4000)) -- select * from #alias_objs order by xtype declare @i int,@n int,@m int,@xt sysname,@name sysname, @flds nvarchar(4000),@types nvarchar(4000), @nulls nvarchar(4000),@outs nvarchar(4000), @mssql2k bit, @done bit select @mssql2k=dbo.fn__ismssql2k() if charindex(''|nosyn|'',@opt)>0 select @mssql2k=1 else select @mssql2k=0 select @i=min(id),@n=max(id) from #alias_objs while (@i<=@n) begin select @done=0 exec sp_executesql N'' select @xt=xtype,@name=obj, @flds=flds, @types=types, @nulls=nulls, @outs=outs from #alias_objs where id=@i '',N'' @i int,@xt sysname out,@name sysname out, @flds nvarchar(4000) out,@types nvarchar(4000) out, @nulls nvarchar(4000) out,@outs nvarchar(4000) out'', @i=@i,@xt=@xt out,@name=@name out,@flds=@flds out,@types=@types out, @nulls=@nulls out,@outs=@outs out select @m=dbo.fn__str_count(@flds,'','') truncate table #src if @mssql2k=1 and @xt=''FN'' begin insert #src select @h1 insert #src select @h2 insert #src select @h3 insert #src select @h4 insert #src select ''create function ''+quotename(@name)+ case when @flds is null then '''' else ''('' end insert #src(line) select '' ''+p.token+'' ''+t.token+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p join dbo.fn__str_params(@types,''|'',default) t on p.pos=t.pos where p.pos>1 insert #src select case when @flds is null then '''' else '')'' end insert #src select ''returns ''+dbo.fn__str_at(@types,''|'',1) insert #src select ''as'' insert #src select ''begin'' insert #src select ''return ''+quotename(@db)+''.dbo.''+quotename(@name)+ case when @flds is null then '''' else ''('' end insert #src(line) select '' ''+p.token+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p where p.pos>1 insert #src select case when @flds is null then '''' else '')'' end insert #src select ''end'' select @done=1 end -- fn if @mssql2k=1 and @xt in (''IF'',''TF'') begin insert #src select @h1 insert #src select @h2 insert #src select @h3 insert #src select @h4 insert #src select ''create function ''+quotename(@name)+ case when @flds is null then '''' else ''('' end insert #src(line) select '' ''+p.token+'' ''+t.token+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p join dbo.fn__str_params(@types,''|'',default) t on p.pos=t.pos where p.pos>1 and p.token like ''@%'' insert #src select case when @flds is null then '''' else '')'' end insert #src select ''returns table '' insert #src select ''as'' insert #src select ''return'' insert #src select ''select * '' insert #src select ''from ''+quotename(@db)+''.dbo.''+quotename(@name)+ case when @flds is null then '''' else ''('' end insert #src select '' ''+p.token+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p where p.pos>1 and p.token like ''@%'' insert #src select case when @flds is null then '''' else '')'' end select @done=1 end -- tf if @mssql2k=1 and @xt=''P'' begin insert #src select @h1 insert #src select @h2 insert #src select @h3 insert #src select @h4 insert #src select ''create proc ''+quotename(@name) insert #src(line) select '' ''+p.token+'' ''+t.token+ case when dbo.fn__str_at(@nulls,'','',p.pos)=''1'' then ''=null'' else '''' end+ case when dbo.fn__str_at(@outs, '','',p.pos)=''1'' then '' out'' else '''' end+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p join dbo.fn__str_params(@types,''|'',default) t on p.pos=t.pos insert #src select ''as'' insert #src select ''exec ''+quotename(@db)+''.dbo.''+quotename(@name) insert #src(line) select '' ''+p.token+ case when dbo.fn__str_at(@outs, '','',p.pos)=''1'' then '' out'' else '''' end+ case when p.pos<@m then '','' else '''' end as line from dbo.fn__str_params(@flds,'','',default) p select @done=1 end -- sp if @mssql2k=0 begin truncate table #src insert #src(line) select ''create synonym ''+quotename(@name)+ '' for ''+quotename(@db)+''.dbo.''+quotename(@name) select @done=1 end if @done=1 begin if @dbg=1 exec sp__print_table ''#src'' else begin declare @lxt nvarchar(2) -- local obj type select @lxt=xtype from sysobjects where id=object_id(@name) -- test to ovverrides correctly if object_id(@name) is null or exists(select null from dbo.fn__script_info(@name,''g'',default) where obj_id=object_id(@name) and val1=''sp__script_alias'') or ''SN''=@lxt -- synonyms are overwritten begin exec sp__drop @name if @dbg=2 exec @ret=sp__script_compile @dbg=1 else exec @ret=sp__script_compile if @ret!=0 exec sp__print_table ''#src'' end else exec @ret=sp__err ''local object "%s" is different'',@proc,@p1=@name end -- overrite/create end -- if done else -- not @done goto err_notp select @i=@i+1 end -- while drop table #src drop table #alias_objs goto ret err_nodb: exec @ret=sp__err ''cannot create self link'',@proc goto ret err_notp: exec @ret=sp__err ''not managed type "%s" for "%s"'',@proc,@p1=@xt,@p2=@name help: exec sp__usage @proc,'' Scope generate a local call to a sp/fn of a twin/origin/master database in mssql2k in mssql2k5 create a shynonym Parameters @db origin db @like name of object to redirect (can use %; null means all sp and fn @excludes name of obj to exclude, separated by comma (can use %) @opt options description nosyn do not use synonym but classic mssql2k forward view/fn/sp Notes If the sp/fn has a parameter @db_name, the sp/fn will be called padding to the original, del value of local "db_name()" Example sp__script_alias ''''master_db'''',''''my_sps%'''' '' select @ret=-1 ret: return @ret end -- sp__script_alias' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_alias: -- ============================================================ sp__script_align select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_align',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130729 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_align') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_align') with nowait goto skip_sp__script_align end if @ver>130729 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_align') with nowait goto skip_sp__script_align end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_align') with nowait if exists( select top 1 null from sys.objects where name='sp__script_align' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_align] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:table v:130729\s.zaglio:added tag t v:130327\s.zaglio:added @noidx and a bug near dropped index v:121004\s.zaglio:a bug near drop of disappeared cols v:121002\s.zaglio:added follow of symbolic src table v:120903\s.zaglio:added drop of constraints v:120903\s.zaglio:managed synonyms loop and no-out bug v:120827\s.zaglio:a bug near dst_db v:120801\s.zaglio:done and tested d:120727\s.zaglio:sp__table_align d:120727\s.zaglio:sp__script_copytable r:120727\s.zaglio:copy a table structure or align existing one t:sp__script_align_test */ CREATE proc sp__script_align @src sysname = null, @dst sysname = null, @opt sysname = null, @dbg int = 0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if (@src is null or @dst is null) and @opt=''||'' goto help -- ============================================================== declaration == declare @svr sysname, @src_db sysname,@dst_db sysname, @src_sch sysname,@dst_sch sysname, @src_obj sysname,@dst_obj sysname, @xtype nvarchar(4), @cod sysname, @opt_src sysname, -- common options for sp__script @crc int, @crlf nvarchar(2), @sql nvarchar(max), @from int, -- from code @to int, -- to code @src_id int, @dst_id int, @notrg bit, -- do not replicate trigger @run bit, @noidx bit, -- do not replicate indexes @end_declare bit create table #src(lno int identity,line nvarchar(4000)) create table #src_src(lno int identity,line nvarchar(4000)) create table #src_def( -- drop table #src_def xtype nvarchar(2), -- type: see table below id int identity, rid int, -- propert parent flags smallint, -- flags depend on tid cod sysname, -- object or property name val sql_variant, -- value of property idx int, -- relative source position start, [end] int -- extra fld for end of code ) create index #src_def on #src_def(xtype,cod) -- tables columns compare to know which add and drop create table #cmp_col (src sysname null,dst sysname null,col_def nvarchar(512)) create table #const(col sysname,name sysname) -- final table with info about differencies create table #cmp( xtype nvarchar(2), cod sysname, src_crc int, dst_crc int, src_from int, src_to int ) create index #cmp on #cmp(xtype,cod) -- =========================================================== initialization == select @notrg=charindex(''|notrg|'',@opt), @noidx=charindex(''|noidx|'',@opt), @run=charindex(''|run|'',@opt), @opt_src=''noprop|nocmt''+case @notrg when 1 then ''|notrg'' else '''' end, @crlf=crlf from fn__sym() -- try to replace local synonym select @src=base_object_name from sys.synonyms where name=@src select @dst=base_object_name from sys.synonyms where name=@dst -- normalize src select @svr=svr, @src_db=isnull(db,db_name()), @src_sch=sch, @src_obj=obj from dbo.fn__parsename(@src,default,1) if not @svr is null and @svr!=dbo.fn__servername(Null) goto err_svr select @src=quotename(@src_db)+''.''+isnull(@src_sch,'''')+''.''+@src_obj select @src_id=object_id(@src) if @dbg=1 exec sp__printf ''-- src_db:%s, src:%s'',@src_db,@src if @src_id is null goto err_onf if not @src_id is null and object_id(@src,''U'') is null goto err_syn -- 121002\s.zaglio: if @db!=db_name() goto err_db -- 121002\s.zaglio: select @xtype=xtype from sysobjects where id=@obj_id -- 121002\s.zaglio: if @xtype!=''u'' goto err_ntt -- normalize dst select @svr=svr, @dst_db=isnull(db,@src_db), @dst_sch=isnull(sch,@src_sch), @dst_obj=obj from dbo.fn__parsename(@dst,default,default) if not @svr is null goto err_svr select @dst=quotename(@dst_db)+''.''+isnull(@dst_sch,'''')+''.''+@dst_obj select @dst_id=object_id(@dst) if not @dst_id is null and object_id(@dst,''U'') is null goto err_syn -- some checks if db_id(@dst_db) is null or db_id(@src_db) is null goto err_dnf if @dst_db=@src_db and @dst_sch=@src_sch and @dst_obj=@src_obj goto err_obj if @dbg=1 exec sp__printf ''-- dst_db:%s, dst:%s'',@dst_db,@dst -- ======================================================== second params chk == -- ===================================================================== body == -- ============================================================ script source == exec @ret=sp__script @src,@opt=@opt_src if @ret!=0 goto err_scr -- alter to destination name insert #src_src select replace(line,@src_obj,@dst_obj) from #src order by lno update #src_def set cod=replace(cod,@src_obj,@dst_obj) -- from - to update src_def set [end]=isnull(b.idx-1,99999) from #src_def src_def left join #src_def b on src_def.id+1=b.id -- prepare code for check select top 100 percent d.xtype,d.cod,s.lno,s.line,checksum(line) crc into #src_crc from #src_src s join #src_def d on s.lno between d.idx and d.[end] order by s.lno -- calc crc of new declare cs_src cursor local for select distinct xtype,cod,idx,[end] from #src_def open cs_src while 1=1 begin fetch next from cs_src into @xtype,@cod,@from,@to if @@fetch_status!=0 break select @crc=null select @crc=isnull(tbl.crc^@crc,tbl.crc) from #src_crc tbl where xtype=@xtype and cod=@cod insert #cmp(xtype,cod,src_crc,src_from,src_to) select @xtype,@cod,@crc,@from,@to end -- cursor cs_src close cs_src deallocate cs_src -- ================================================ script destination object == if not @dst_id is null begin truncate table #src_def truncate table #src exec @ret=sp__script @dst,@opt=@opt_src if @ret!=0 goto err_scr -- prepare code for check select top 100 percent d.xtype,d.cod,s.lno,s.line,checksum(line) crc into #dst_crc from #src s join ( select -- a.id,b.id, a.xtype,a.flags,a.cod, a.idx as start,isnull(b.idx-1,99999) [end] from #src_def a left join #src_def b on a.id+1=b.id ) d on s.lno between d.start and d.[end] order by s.lno -- calc crc of new declare cs_dst cursor local for select distinct xtype,cod from #src_def open cs_dst while 1=1 begin fetch next from cs_dst into @xtype,@cod if @@fetch_status!=0 break select @crc=null select @crc=isnull(tbl.crc^@crc,tbl.crc) from #dst_crc tbl where xtype=@xtype and cod=@cod update #cmp set dst_crc=@crc where xtype=@xtype and cod=@cod if @@rowcount=0 insert #cmp(xtype,cod,dst_crc) select @xtype,@cod,@crc end -- cursor cs_dst close cs_dst deallocate cs_dst truncate table #src insert #src select ''use [''+@dst_db+''] '' -- check if table is changed if exists( select null from #cmp where xtype=''u'' and src_crc!=dst_crc ) begin select @sql= '' -- compare fields insert #cmp_col select src.name src_col,dst.name dst_col, dbo.fn__sql_def_col( c.tablename,null, dbo.fn__str_quote(c.columnname,''''[]''''), null,c.typename, c.[length],c.[precision],c.scale, c.allownulls,c.dridefaultname, c.dridefaultcode,c.[identity], c.iscomputed,c.computedtext,null/*chkname*/, null/*chkcode*/,c.collation,null,null ) as line from ( select name from [%src_db%]..syscolumns where id=%src_id% ) src full outer join ( select name from [%dst_db%]..syscolumns dst where dst.id=%dst_id% ) dst on src.name=dst.name left join [%src_db%]..fn__script_col(%src_id%) c on c.columnname=src.name where 1=1 and (src.name is null or dst.name is null) -- acquire dst constraints insert #const(col,name) select c.name col,object_name(d.constid,db_id(''''%dst_db%'''')) cnts from [%dst_db%]..sysconstraints d join [%dst_db%]..syscolumns c on c.id=%dst_id% and c.colid=d.colid where d.id=%dst_id% '' exec sp__str_replace @sql out, ''%dst%|%dst_db%|%src_obj%|%src_id%|%dst_id%|%src_db%'', @dst,@dst_db,@src_obj,@src_id,@dst_id,@src_db if @dbg>0 exec sp__printsql @sql -- exec sp__printsql @sql exec(@sql) -- drop idx before columns to avoid column used problem -- drop pk if changed insert #src select '''' insert #src select ''-- drop pk if changed'' insert #src select ''alter table ''+@dst_obj+'' drop constraint ''+quotename(cod) from #cmp where src_crc!=dst_crc -- nulls excluded and xtype in (''pk'') -- drop index that not exists anymore insert #src select '''' insert #src select ''-- drop dest idx that not exists anymore'' insert #src select ''drop index ''+quotename(@dst_obj)+''.''+quotename(cod) from #cmp where src_crc is null and xtype in (''ix'') insert #src select '''' insert #src select ''-- drop old constraints'' insert #src select ''alter table ''+@dst_obj+'' drop constraint ''+quotename(con.name) from #cmp_col col join #const con on con.col=col.dst where src is null insert #src select '''' insert #src select ''-- drop old columns'' insert #src select ''alter table ''+@dst_obj+'' drop column ''+quotename(dst) from #cmp_col where src is null insert #src select '''' insert #src select ''-- add new columns'' insert #src select ''alter table ''+@dst_obj+'' add ''+cc.col_def from #cmp_col cc where cc.dst is null end -- table changed if @noidx=0 begin insert #src select '''' insert #src select ''-- add new indexes'' insert #src select line from #src_src src join #cmp cmp on src.lno between cmp.src_from and cmp.src_to where dst_crc is null and xtype in (''ix'',''pk'') insert #src select '''' insert #src select ''-- drop all changed or dropped indexes'' insert #src select ''drop index ''+quotename(@dst_obj)+''.''+quotename(cod) from #cmp where (src_crc!=dst_crc or src_crc is null) and xtype in (''ix'') insert #src select '''' insert #src select ''-- re-create all changed indexes'' insert #src select line from #src_src src join #cmp cmp on src.lno between cmp.src_from and cmp.src_to where src_crc!=dst_crc -- nulls excluded and xtype in (''ix'',''pk'') end if @notrg=0 begin insert #src select '''' insert #src select ''-- drop disappeared triggers'' insert #src select ''drop trigger ''+quotename(cod) from #cmp cmp where (src_crc is null) and xtype in (''tr'') insert #src select '''' insert #src select ''-- align triggers'' insert #src select line from #src_src src join #cmp cmp on src.lno between cmp.src_from and cmp.src_to where (src_crc!=dst_crc or dst_crc is null) and xtype in (''tr'') end -- notrg end -- script dst else -- if not exists begin truncate table #src insert #src select ''use [''+@dst_db+''] '' insert #src select line from #src_src order by lno end -- debug info if @dbg>0 begin select *, case when isnull(src_crc,0)!=isnull(dst_crc,0) then ''*'' else '''' end [*] from #cmp end -- ====================================================== script print or run == if @dbg>0 or @run=0 exec sp__print_table ''#src'' if @run>0 begin select @sql=isnull(@sql,'''')+isnull(line,'''')+@crlf from #src order by lno if @sql is null goto err_sql exec(@sql) if @@error!=0 goto err_sql end -- ================================================================== dispose == dispose: drop table #cmp drop table #cmp_col drop table #src_crc drop table #src_src if not object_id(''tempdb..#dst_crc'') is null drop table #dst_crc drop table #src_def drop table #src goto ret -- =================================================================== errors == err_svr: exec @ret=sp__err ''server as source or destination is not managed'', @proc goto ret err_db: exec @ret=sp__err ''source object must come from current db'', @proc goto ret err_obj: exec @ret=sp__err ''cannot replicate object on itself'', @proc goto ret err_syn: exec @ret=sp__err ''destination object exists but is not a table'', @proc goto ret err_onf: exec @ret=sp__err ''source "%s" not found'', @proc,@p1=@src_obj goto ret err_dnf: exec @ret=sp__err ''destination db "%s" not found'', @proc,@p1=@dst_db goto ret err_ntt: exec @ret=sp__err ''source is not a table'', @proc goto ret err_sql: exec sp__printsql @sql exec @ret=sp__err ''inside sql'', @proc err_scr: goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create a copy of table structure with different name and db; Notes * create destination table if not exists * add index/pk if not exists on destination * drop destination index/pk if not exist in source * add/drop column if not exists or disappeared * comment/property are not aligned Parameters @src source table @dst destination name (can contain a different db) can be a synonym that will be expanded @opt options notrg do not align triggers noidx do not align indexes run run script immediatelly @dbg debug 1 print code instead run it (same as not specify "run") Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_align' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_align: -- ========================================================= sp__script_assembly select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_assembly',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121104 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_assembly') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_assembly') with nowait goto skip_sp__script_assembly end if @ver>121104 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_assembly') with nowait goto skip_sp__script_assembly end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_assembly') with nowait if exists( select top 1 null from sys.objects where name='sp__script_assembly' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_assembly] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:121104\s.zaglio: compile behaviour change r:121028\s.zaglio: done the scripting d:121027\s.zaglio: sp__assembly r:121020\s.zaglio: refined r:100424\s.zaglio: utility for assembly integration */ CREATE proc sp__script_assembly @assembly sysname = null, @cs nvarchar(max) = null, -- c# source @opt sysname = null, @dbg int = null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 declare @path nvarchar(1024),@cmd nvarchar(1024), @csc nvarchar(1024),@ext sysname, @dll nvarchar(1024),@src nvarchar(1024), @sql nvarchar(max),@tmp nvarchar(1024), @content varbinary(max),@i int,@crlf nvarchar(2), @asm_id int,@nets nvarchar(256) declare @paths table(path nvarchar(1024),cod nvarchar(32)) create table #out(lno int identity,line nvarchar(4000)) select @crlf=crlf from fn__sym() -- searcing compilers select @cmd=''dir "%SystemRoot%"\"Microsoft.NET"\csc.exe/s/b'' insert @paths(path) exec xp_cmdshell @cmd select @nets=''2.0|3.0|3.5|4.0|4.5'' -- 32 update p set cod=token+''x32'' from @paths p cross join dbo.fn__str_table(@nets,''|'') where path like ''%\Framework\v''+token+''%\csc.exe'' -- 64 update p set cod=token+''x64'' from @paths p cross join dbo.fn__str_table(@nets,''|'') where path like ''%\Framework64\v''+token+''%\csc.exe'' select top 1 @csc=path from @paths where charindex(cod,@opt)>0 if @csc is null begin select top 1 @csc=path from @paths where cod=''2.0x32'' if @dbg=1 exec sp__printf ''-- default compiler:%s'',@csc end else if @dbg=1 exec sp__printf ''-- forced compiler:%s'',@csc if @csc is null or isnull(@assembly,'''')='''' goto help if exists(select * from sys.assemblies where name=@assembly) goto err_asm -- compile into new assembly exec sp__get_temp_dir @path out select @tmp=''sp__assembly_''+replace(cast(newid() as sysname),''-'',''_'') select @src=@path+''\''+@tmp+''.cs'' select @dll=@path+''\''+@tmp+''.dll'' if @dbg=1 exec sp__printf ''-- src:%s, dll=%s'',@src,@dll exec sp__file_write_stream @src,@txt=@cs -- select @cmd=''cd "''+@path+''"&''+@csc .. select @cmd=@csc+'' /t:library /out:''+@dll+'' ''+@src if @dbg!=0 exec sp__printf ''-- cmd:%s'',@cmd insert #out exec @ret=xp_cmdshell @cmd if @ret!=0 or exists(select null from #out where line like ''%error%'') goto err_csc select @sql=''create assembly %assembly% authorization [dbo] '' +''from ''''%dll%'''' with permission_set = safe'' exec sp__str_replace @sql out,''%assembly%|%dll%'',@assembly,@dll exec(@sql) if @@error!=0 goto err_cra /* select * from sys.assemblies select * from sys.assembly_files select * from sys.assembly_references select so.name, so.[type], schema_name(so.schema_id) as [schema], asmbly.name [assembly], asmbly.permission_set_desc, am.assembly_class, am.assembly_method from sys.assembly_modules am inner join sys.assemblies asmbly on asmbly.assembly_id = am.assembly_id and asmbly.name not like ''microsoft%'' inner join sys.objects so on so.object_id = am.object_id union select at.name, ''type'' as [type], schema_name(at.schema_id) as [schema], asmbly.name, asmbly.permission_set_desc, at.assembly_class, null as [assembly_method] from sys.assembly_types at inner join sys.assemblies asmbly on asmbly.assembly_id = at.assembly_id and asmbly.name not like ''microsoft%'' order by 4, 2, 1 */ select @asm_id=assembly_id from sys.assemblies where name=@assembly if @asm_id is null goto err_asm select @content=content from sys.assembly_files where assembly_id=@asm_id exec(''drop assembly ''+@assembly) select @i=1,@sql=null while @i<=len(@content) select @sql=isnull(@sql+''\''+@crlf,'''') +substring(dbo.fn__hex(substring(@content,@i,@i+64)),3,128), @i=@i+64 select @sql=''create assembly ''+@assembly+@crlf +''from 0x\''+@crlf+@sql+@crlf +''with permission_set = safe''+@crlf exec sp__printsql @sql /* CREATE FUNCTION [fn_compress] ( @compressedBlob varbinary(MAX)) RETURNS varbinary(MAX) AS EXTERNAL NAME %assembly%.%class%.%fn%; select dbo.fn_compress(convert(varbinary(max),''test'')) */ -- from http://www.codeproject.com/KB/database/blob_compress.aspx /* -- drop assembly utility_core -- drop function fn__compress drop function fn__decompress sp__script_assembly ''utility_core'','' using System; using System.IO; using System.IO.Compression; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public partial class utils { // Setting function characteristics [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic=true, DataAccess=DataAccessKind.None)] public static SqlBytes fn__compress(SqlBytes blob) { if (blob.IsNull) return blob; // Retrieving BLOB data byte[] blobData = blob.Buffer; // Preparing for compression MemoryStream compressedData = new MemoryStream(); DeflateStream compressor = new DeflateStream(compressedData, CompressionMode.Compress, true); // Writting uncompressed data using a DeflateStream compressor compressor.Write(blobData, 0, blobData.Length); // Clossing compressor to allow ALL compressed bytes to be written compressor.Flush(); compressor.Close(); compressor = null; return new SqlBytes(compressedData); // Returning compressed blob } public static SqlBytes fn__decompress(SqlBytes compressedBlob) { if (compressedBlob.IsNull) return compressedBlob; // Preparing to read data from compressed stream DeflateStream decompressor = new DeflateStream(compressedBlob.Stream, CompressionMode.Decompress, true); // Initializing variables int bytesRead = 1; int chunkSize = 10000; byte[] chunk = new byte[chunkSize]; // Preparing destination stream to hold decompressed data MemoryStream decompressedData = new MemoryStream(); try { // Reading from compressed stream while ((bytesRead = decompressor.Read(chunk, 0, chunkSize)) > 0) { // Writting decompressed data decompressedData.Write(chunk, 0, bytesRead); } } catch (Exception) { throw; // Nothing to do... } finally { decompressor.Close(); // Cleaning up decompressor = null; } return new SqlBytes(decompressedData); // Returning a decompressed BLOB } }; '' ,@dbg=1 */ dispose: goto ret -- =================================================================== errors == err_cra: exec @ret=sp__err ''creating assembly'',@opt=''noerr'' goto ret err_csc: exec sp__print_table ''#out'' exec @ret=sp__err ''compiler'',@proc goto ret err_asm: exec @ret=sp__err ''assembly already exists'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope compile a source stored into #src or from @file into a @file.dll Notes * CLR must be active (see sp__util_advopt) * by default compile for .NET 2.0 32bit * actually only C# sources are considered Parameters @assembly assembly name @cs is the c# source to compile and integrate @opt options 2.0x32 compile for .NET 2.0 32bit others are: 3.0x32,3.5x32,4.0x32 2.0x64 compile for .NET2.0 64bit others are: 3.0x64,3.5x64,4.0x64 @dbg not used '' exec sp__printf ''The C# compiler path is:%s\n'',@csc select @csc=@csc+'' /?'' insert #out exec xp_cmdshell @csc exec sp__print_table ''#out'' -- ===================================================================== exit == ret: drop table #out -- remove temporary files select @cmd=''del /q ''+@dll exec xp_cmdshell @cmd,no_output select @cmd=''del /q ''+@src exec xp_cmdshell @cmd,no_output return @ret end -- sp__assembly' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_assembly: -- ============================================================= sp__script_code select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_code',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130729.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_code') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_code') with nowait goto skip_sp__script_code end if @ver>130729.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_code') with nowait goto skip_sp__script_code end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_code') with nowait if exists( select top 1 null from sys.objects where name='sp__script_code' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_code] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:130729.1000\s.zaglio:managed #objs v:121012\s.zaglio:option to remove top comments v:120730\s.zaglio:adding support for #src_def v:120717\s.zaglio:replaced {tab} with 4 spaces v:120622\s.zaglio:added related option v:120504\s.zaglio:managed drop option of history v:120213\s.zaglio:around @obj as hex value v:120207\s.zaglio:adapted to new log_ddl v:111028\s.zaglio:script of trigger into sp_execute v:110721\s.zaglio:added debug to test anomalous chars as � that boh... and used fn__ntext_to_lines v:110628\s.zaglio:added scripting of trigger on db v:110406\s.zaglio:on mssql2k5 uses sys.sql_modules instead of syscomments v:110329\s.zaglio:added @obj as # to script old revisions and removed @out v:100919.1000\s.zaglio:more compatible mssql2k v:100919\s.zaglio:strip end comments to not duplicate it ad every sp__script v:100411\s.zaglio:added synonym v:100328\s.zaglio: version 3.0 of scripting utility for views,proc,function,trigrs t:sp__script_code ''sp__script_code'',@dbg=1 t:sp__script ''sp__script_code'' t:sp__script_ole ''sp__script_code'' t:sp__script_code ''obj_not_exist'' t:sp__script ''sp__script'',@dbg=1 t: create table #src(lno int identity,line nvarchar(4000)) exec sp__Script_code ''sp__Script_code'' select * from #src order by lno drop table #src t: create proc test as print ''hello'' exec sp__script_code ''test'' drop proc test t: create synonym stest for sp__script_code exec sp__script_code ''stest'' exec sp__script ''stest'' drop synonym stest t:sp__script_code 230 -- sp__script_trace t:sp__Script_code ''tr__script_trace_db'' t:sp__script_code ''sp__script_code'',@dbg=1,@opt=''notcm'' */ CREATE proc [dbo].[sp__script_code] @obj sysname=null, @opt sysname=null, @ntext ntext=null, -- dummies @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @obj is null goto help if @dbg=1 exec sp__printf ''-- sp__script_code(%s,%s)'',@obj,@opt -- unicode test:"日本" declare @lno_begin int,@lno_end int, @id int,@db sysname,@sch sysname,@sch_id int, @obj_ex sysname,@obj_in sysname, -- @def bit, -- must stay in sp__Script @end_declare bit declare @src table(lno int identity primary key,line nvarchar(4000)) declare @buf nvarchar(4000),@line nvarchar(4000), @s int,@k int,@i int,@n int,@j int,@old nvarchar(4000), @c nchar(1),@cr nchar(1),@lf nchar(1),@crlf nvarchar(2), @xtype nvarchar(4),@spaces varchar(4),@tab char(1) select @cr=cr,@lf=lf,@crlf=crlf,@tab=tab,@spaces='' '' from fn__sym() if left(@obj,1)=''#'' begin select top 1 @ntext=definition from tempdb.sys.sql_modules with (nolock) where object_id=object_id(''tempdb..''+@obj) print @ntext goto fill_src end select -- @def=isnull(object_id(''tempdb..#src_def''),0), @db =parsename(@obj,3), @sch=parsename(@obj,2), @obj=parsename(@obj,1) if @db is null select @db=db_name() select @sch=[name],@sch_id=id from dbo.fn__schema_of(@obj) select @obj_ex = quotename(@db)+''.'' + coalesce(quotename(@sch),'''')+''.'' + quotename(@obj) -- copy from syscomments or from log_ddl into internal table if left(@obj,2)=''0x'' begin select @id=dbo.fn__hex2int(@obj) select @ntext=txt from tids,log_ddl tbl where tbl.tid=tids.code and tbl.id=@id -- sp__script 80000007 -- sp__script_history if @@rowcount=0 goto err_nof end else begin -- get type select @id=id,@xtype=xtype from sysobjects where [name]=@obj -- if is a synonym if @xtype=''SN'' begin insert #src(line) select ''create ''+lower(sy.type_desc)+'' '' +sc.name + ''.'' + sy.name -- as synonym_name +'' for ''+sy.base_object_name from sys.synonyms sy join sys.schemas sc on sc.schema_id = sy.schema_id where sy.[object_id] = @id goto ret end -- synonym if @id is null select @id=object_id from sys.triggers where [name]=@obj if @id is null goto err_nof select top 1 @ntext=definition from sys.sql_modules with (nolock) where object_id=@id end -- fill @blob -- ########################## -- ## -- ## fill @src -- ## -- ######################################################## fill_src: insert @src(line) select line from fn__ntext_to_lines(@ntext,0 /*remove crlf */) update @src set line=rtrim(line) -- remote top comments /* */ if charindex(''|sqlite|'',@opt)>0 or charindex(''|notcm|'',@opt)>0 begin select @line=null select top 1 @line=line from @src where line like ''/*%'' or line like ''--%'' order by lno if @line like ''--%'' delete from @src where lno<( select top 1 lno from @src where not line like ''--%'' ) -- NB: nested comment are not managed if @line like ''/*%'' delete from @src where lno<=( select top 1 lno from @src where line like ''%*/'' ) end -- delete top comments -- ######################################################## select @lno_begin=min(lno),@lno_end=max(lno) from @src -- strip blank line above select top 1 @lno_begin=lno from @src where line!='''' and lno>=@lno_begin order by lno select top 1 @lno_end=lno from @src where line!='''' and lno<=@lno_end order by lno desc -- strip end comments to not duplicate it ad every sp__script if exists( select top 1 null from @src where left(line,16)=''exec sp__comment'' and lno<=@lno_end order by lno desc ) select top 1 @lno_end=lno from @src where left(line,16)!=''exec sp__comment'' and lno<=@lno_end order by lno desc -- if is a trigger, require GO so we encapsulate into execute if (@xtype=''TR'' and charindex(''|related|'',@opt)!=0) or (left(@obj,2)=''0x'' and charindex(''|drop|'',@opt)!=0) -- and charindex(''|DROP|'',@opt)=0 begin -- note: this manage one single code update @src set line=replace( case when right(line,1)=''\'' -- this solve escape problem then line+'' '' else line end,'''''''','''''''''''' ) update @src set line=''exec sp_executesql N''''''+line where lno=@lno_begin update @src set line=line+'''''''' where lno=@lno_end end -- encapsulate if object_id(''tempdb..#src'') is null select line from @src where lno between @lno_begin and @lno_end order by lno else insert #src(line) select replace(line,@tab,@spaces) from @src where lno between @lno_begin and @lno_end order by lno -- nb: charindex search into 4000 chars max goto ret -- =================================================================== errors == err_nof: exec @ret=sp__err ''object or release %s not found'',@proc,@p1=@obj goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope of %proc% script objects tha has code into syscomments(mssql2k) or sys.sql_modules(mssql2k5) or log_ddl Notes {tab} is replaced with 4 spaces Parameters @obj is the object name @ntext is for internal use #src if declared store result into this otherwise output as select @opt options description drop enclose code into sp_executesql statement related when a trigger is under a table, code is encapsulated into a sp_executesql notcm do not script top comments '' select @ret=-1 ret: return @ret end -- sp__script_code' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_code: -- ========================================================== sp__script_compile select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_compile',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130605 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_compile') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_compile') with nowait goto skip_sp__script_compile end if @ver>130605 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_compile') with nowait goto skip_sp__script_compile end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_compile') with nowait if exists( select top 1 null from sys.objects where name='sp__script_compile' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_compile] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:130605\s.zaglio: removed printf deprecated parameters v:120920\s.zaglio:ms2k5 version because some strange @crlf loses v:111205\s.zaglio:added noalter option v:110415\s.zaglio:added error return value v:110324\s.zaglio:added @opt and dep v:110213\s.zaglio:about automatic alter v:111130\s.zaglio:improved recodnition of "create xxxx" v:100919.1000\s.zaglio:improved help and more compatible with mssql2k v:100703\s.zaglio:do not alter create table v:100612\s.zaglio:more help v:100424\s.zaglio:added -- noalter as pragma option v:100405\s.zaglio:retested compile of @obj (saving original before!!!) v:100404\s.zaglio:added control for 100 blocks and null lines and chunking v:100328\s.zaglio:renamed old sp__script_recompile & integrated sp__Scrit_run v:100118\s.zaglio:added to group script v:091018\s.zaglio: recompile a big procedure passe with #src t:sp__script_compile ''sp__script_compile'',@dbg=1 t:sp__script_compile ''sp__script_table'',@dbg=1 t:exec sp__script_compile ''flags'',@opt=''dep'' t:exec sp__script_trace_db ''install'' */ CREATE proc [dbo].[sp__script_compile] @obj sysname=null, -- an sp/function/view to recompile or #src @opt sysname=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') declare @i int,@n int,@s int,@line nvarchar(4000),@id int, @crlf nchar(2),@cr nchar(1),@m int,@block nvarchar(4000), @trace bit,@noalter bit declare @src table(lno int identity(1,1) primary key, line nvarchar(4000)) select @crlf=crlf,@cr=cr, @trace=charindex(''|trace|'',@opt), @noalter=charindex(''|noalter|'',@opt) from dbo.fn__sym() if @obj is null and not object_id(''tempdb..#src'') is null select @obj=''#src'' if @obj is null goto help -- read first line to determine if is a single or multiple script if @obj=''#src'' begin declare cs cursor local for select coalesce(line,N'''') from #src order by lno open cs fetch next from cs into @line if @line like ''--%script%'' begin -- multi script while 1=1 begin fetch next from cs into @line if @@fetch_status!=0 break if @dbg=1 exec sp__printf @line exec(@line) if @@error!=0 begin exec sp__printf ''error in:\%s'',@line select @ret=-2 goto ret end end -- while close cs deallocate cs goto ret end -- execute line by line -- group lines of single script into blocks select @block='''',@n=0,@i=0 while 1=1 begin select @i=@i+1 if @dbg=1 exec sp__printf ''%d %s'',@i,@line if len(@block)+len(@line)+len(@crlf)>4000 begin insert @src select @block select @block='''',@n=@n+1 end select @block=@block+@line+@crlf fetch next from cs into @line if @@fetch_status!=0 break end -- while if len(@block)>0 -- last chunk begin insert @src select @block select @block='''',@n=@n+1 end if @n>100 goto err_max close cs deallocate cs goto run end -- load lines of single script into blocks -- used as store for sequence of objects create table #dep( id int identity, uses bit null, obj sysname, buildin sysname null, usr sysname null, comment sysname null, [level] int null ) if charindex(''|dep|'',@opt)>0 exec sp__script_dep @obj,@opt=''uses'' else insert #dep(obj) select @obj if @dbg=1 select * from #dep order by id declare objs cursor local for select obj from #dep order by id open objs while 1=1 begin select @obj=null fetch next from objs into @obj if @@fetch_status!=0 break select @id=object_id(@obj) if @dbg=1 exec sp__printf ''\n## fetched obj "%s" id "%d"'',@obj,@id if @trace=1 exec sp__printf ''-- recompiling: %s'',@obj -- load obj source info memory table if @id is null goto err_onf delete from @src insert into @src(line) select [text] from syscomments where id=@id order by colid -- change create into alter select top 1 @i=lno,@line=line from @src order by lno declare @key1 sysname,@key2 sysname select @key1=case when pos=1 then token else @key1 end, @key2=case when pos=2 then token else @key2 end from dbo.fn__str_table(@line,'''') where pos in (1,2) -- specific generated code so existance is checked by caller select top 1 @n=lno,@line=line,@i=charindex(@crlf+''create '',@line)+len(@crlf) from @src where charindex(@crlf+''create '',@line)>0 order by lno declare @ln nvarchar(4000) select @ln=substring(@line,@i,charindex(@crlf,@line,@i)-@i) if @dbg=1 exec sp__printf ''-- recompile: chg create to alter at line:%d, pos:%d, ln:%s'',@n,@i,@ln /*if @dbg=1 begin -- sp__script_compile ''sp__script_compile'',@dbg=1 exec sp__printf ''i=%d, n=%d'',@i,@n print substring(@line,@i,20) end*/ select @key1=case when pos=1 then token else @key1 end, @key2=case when pos=2 then token else @key2 end from dbo.fn__str_table(@ln,'''') where pos in (1,2) select @line=substring(@line,1,@i-1) +''alter''+substring(@line,@i+len(@key1),4000) if @dbg=1 exec sp__printf ''k1:%s, k2:%s, ln:%s'',@key1,@key2,@ln select @ln=substring(@line,@i-1,charindex(@crlf,@line,@i)-@i) update @src set line=@line where lno=@n if @dbg=1 exec sp__printf ''@i=%d'',@i run: /* select * into #tmp from @src order by lno exec sp__print_table ''#tmp'' return 0 */ /* this generate the code to execute a source bigger than 4000 chrs declare @sql nvarchar(4000),@nullize nvarchar(4000) declare @i int,@n int exec sp__printf ''select top 1 @i=lno from @src order by lno'' select @i=0,@n=99,@sql='''' while @i<=@n begin exec sp__printf ''declare @s%d nvarchar(4000);select @s%d=null,@s%d=line from @src where lno=@i+%d'', @i,@i,@i,@i select @sql=@sql+''@s''+convert(sysname,@i)+ case when @i<@n then ''+'' else '''' end+ case when @i%12=0 then nchar(13)+nchar(10) else '''' end select @i=@i+1 end exec sp__printf '''' exec sp__printf ''if @dbg=1 exec sp__printsql @s0'' exec sp__printf '''' exec sp__printsql ''exec('',@sql,'')'' -- copy and paste the result below, after close of comment */ declare @sql nvarchar(max) select @sql= '''' select @sql=@sql+line from @src order by lno if @sql is null goto err_cod exec(@sql) select @ret=@@error if @ret!=0 exec sp__printsql @sql if @obj=''#src'' goto ret end -- while objs dispose: close objs deallocate objs goto ret -- =================================================================== errors == err_max: exec sp__err ''%d blocks but max 100 admitted'',@proc,@p1=@m goto ret err_onf: exec @ret=sp__err ''object not found'',@proc goto ret err_cod: exec @ret=sp__err ''inside code error'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope Recompile an object or compile a source given in #src if 1st line is "-- script" esecute each line present in #src if 1st line is "-- noalter" do not automatically change create into alter (see also option "noalter") Parameters @obj name of proc,view,function, etc. @opt options dep do not recompile @obj but all objects that use it (sp__script_dep ''''tids'''',@opt=''''uses'''') noalter do not automatically change Table create table #src(lno int identity,line nvarchar(4000)) insert #src(line) select ''''-- scripts'''' insert #src(line) select ''''print ''''''''row1'''''''''''' insert #src(line) select ''''print ''''''''row2'''''''''''' exec sp__script_compile truncate table #src insert #src(line) select ''''create proc sp_test as print ''''''''sp_test'''''''''''' exec sp__script_compile exec sp_test drop proc sp_test drop table #src '' select @ret=-1 ret: return @ret end -- [sp__script_compile]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_compile: -- ========================================================= sp__script_compress select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_compress',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130703 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_compress') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_compress') with nowait goto skip_sp__script_compress end if @ver>130703 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_compress') with nowait goto skip_sp__script_compress end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_compress') with nowait if exists( select top 1 null from sys.objects where name='sp__script_compress' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_compress] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:binary r:130703\s.zaglio: compress #src content and replace it with hex code */ create proc sp__script_compress @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, @i int,@n int, -- index, counter @sql nvarchar(max), @bin_sql varbinary(max), @line nvarchar(4000), @crlf nvarchar(2), -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @crlf=crlf, @end_declare=1 from fn__sym() -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if object_id(''tempdb..#src'') is null goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- sp__script_group ''utility'',@opt=''bin'' select @n=count(*) from #src exec sp__printf ''-- %d lines in #src'',@n select @sql= stuff( (select @crlf+line -- select name from #src order by lno for xml path(''''), type).value(''.'', ''nvarchar(max)'') ,1,len(@crlf),'''') exec sp__printsql @sql select @bin_sql=dbo.fn__compress(cast(@sql as varbinary(max))) select @n=len(@bin_sql) exec sp__printf ''-- compressed size:%d'',@n truncate table #src select @i=1 while (@i 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_compress' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_compress: -- ============================================================= sp__script_data select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_data',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=111229 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_data') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_data') with nowait goto skip_sp__script_data end if @ver>111229 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_data') with nowait goto skip_sp__script_data end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_data') with nowait if exists( select top 1 null from sys.objects where name='sp__script_data' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_data] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:insert v:111229\s.zaglio: adapted to new sp__script_template r:111228\s.zaglio: adapting to new sp__script_template r:111227\s.zaglio: adapting to new sp__script_template r:111223\s.zaglio: adapting to new sp__script_template v:111103\s.zaglio: added bincols option and db check v:111031\s.zaglio: added N before '' v:110824\s.zaglio: adapted to new sp__script_template v:110707\s.zaglio: a small bug near ident v:110706.1221\s.zaglio: a bug near truncate and added restore v:110705\s.zaglio: added @opt v:110518\s.zaglio: injected strings with '' v:100919\s.zaglio: added insert from #tmp (useful to find error string or bin truncated) v:100601\s.zaglio: added @top and @where v:100514\s.zaglio: print script to insert data t: create table test_script_data(id int identity, a sysname, d datetime default(getdate())) insert test_script_data(a) select ''one'' insert test_script_data(a) select ''two'' exec sp__script_data ''test_script_data'' exec sp__script_data ''test_script_data'',@where=''a="two"'' exec sp__script_data ''test_script_data'',@top=1,@dbg=1 select * into #t from test_script_data exec sp__script_data ''#t'' -- TODO drop table test_script_data drop table #t */ CREATE proc sp__script_data @tbl sysname=null, @where sysname=null, @top sysname=null, @opt sysname=null, @dbg bit=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0,@dbg=isnull(@dbg,0), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @tbl is null goto help if left(@tbl,1)!=''#'' and object_id(@tbl) is null goto err_noo if left(@tbl,1)=''#'' and object_id(''tempdb..''+@tbl) is null goto err_noo select @tbl=dbo.fn__sql_unquotename(@tbl) if not @where is null and (dbo.fn__occurrence(@where,''"'') % 2)=0 select @where=replace(@where,''"'','''''''') declare @flds nvarchar(4000), @oflds nvarchar(4000),@merge bit,@restore bit,@scramble bit, @dst sysname,@n int, @src sysname, @excludes sysname,@noinc bit, @identity sysname -- main section declare @bincols table ([name] sysname) if charindex(''|bincols:'',@opt)>0 begin insert @bincols([name]) select token from dbo.fn__str_table(dbo.fn__str_between(@opt,''|bincols:'',''|'',default),''|'') end -- bincols create table #tpl(lno int identity primary key,line nvarchar(4000)) create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) -- first define the template insert #tpl(line) select line from dbo.fn__ntext_to_lines('' %safety%: if db_name()=''''%db%'''' begin raiserror(''''for safety reasons I can not run on the same database'''',10,1) with nowait goto safe_skip end -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %before%: %safety% select top 0 * into [%dst%] from [%src%] -- |merge| alter table [%dst%] disable trigger all set identity_insert [%dst%] on -- |ident| truncate table [%dst%] -- |where| -- truncate table [%dst%] -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %after%: exec sp__merge "%src%", -- |merge| @from="%dst%", -- |merge| @keys="???", -- |merge| @flds_cmp="%flds%" -- |merge| set identity_insert [%dst%] off -- |ident| alter table [%dst%] enable trigger all '',0) select @identity=[name] from syscolumns where id=object_id(@tbl) and columnproperty(id,[name],''IsIdentity'')=1 select @merge=charindex(''|merge|'',@opt), @restore=charindex(''|restore|'',@opt), @scramble=charindex(''|scramble|'',@opt), @noinc=charindex(''|noinc|'',@opt), @flds=dbo.fn__flds_of(@tbl,''|'',case when @noinc=1 then @identity else null end), @oflds=replace(dbo.fn__flds_quotename(@flds,''|''),''|'','',''), @dst=case when @merge=1 then ''#'' else '''' end + @tbl, @src=@tbl, @excludes='''' create table #out (lno int identity(10,10),line nvarchar(4000)) create table #src (lno int identity,line nvarchar(4000)) if @identity is null and @noinc=0 select @excludes=@excludes+''|ident'' if @merge=0 select @excludes=@excludes+''|merge'' -- insert #tpl_sec select ''%fields%'', case when @scramble=1 and (t.[name] like ''%char'' or t.name in (''sysname'')) then ''dbo.fn__str_scramble(''+dbo.fn__str_quote(c.[name],''[]'')+ '',rand(checksum(newid()))) as [''+c.[name]+'']'' else dbo.fn__str_quote(c.[name],''[]'') end + case when colorder=(select max(colorder) from syscolumns where id=object_id(@tbl)) then '''' else '','' end from syscolumns c join systypes t on c.xusertype=t.xusertype where id=object_id(@tbl) order by colorder -- create the script to script the select of data and store into #out insert #src(line) select ''insert #out(line) '' insert #src(line) select ''select ''+coalesce(''top ''+@top+'' '','''')+'' '' -- '' ''''N'''''' -- insert #src(line) select ''''''insert [''+@dst+''](''+@oflds+'') '' -- sp__Script_data ''sios_dict'',@opt=''restore'' -- sp__Script_data ''sios_dict'',@opt=''bincols:cod'' insert #src(line) select ''+''+ case -- if binary column when exists(select null from @bincols where [name]=c.[name]) then ''coalesce(dbo.fn__hex(convert(varbinary(8000),''+dbo.fn__str_quote(c.[name],''[]'')+'')),''''null'''')'' -- if numeric field when t.[name] like ''%int'' or t.name in (''real'',''float'',''decimal'',''numeric'') then ''coalesce(convert(nvarchar(4000),''+ dbo.fn__str_quote(c.[name],''[]'')+ '',126),''''null'''')'' else replace( ''coalesce("N"""+replace(convert(nvarchar(4000),'' + case when @scramble=1 and (t.[name] like ''%char'' or t.name in (''sysname'')) then ''dbo.fn__str_scramble(''+dbo.fn__str_quote(c.[name],''[]'')+ '',rand(checksum(newid())))'' else dbo.fn__str_quote(c.[name],''[]'') end + '',126),"""","""""")+"""","null")'', ''"'','''''''' ) end+ case when colid= (select max(colid) from syscolumns where id=object_id(@tbl) ) then '''' else ''+'''','''''' end from syscolumns c join systypes t on c.xusertype=t.xusertype where c.id=object_id(@tbl) and ( -- exclude identity if opt "noinc" @identity is null or @noinc=0 or (@noinc=1 and @identity!=c.[name]) ) order by c.colorder insert #src(line) select '' as line '' insert #src(line) select ''from ''+quotename(@tbl) if not @where is null insert #src(line) select ''where ''+@where if @dbg=1 exec sp__print_table ''#src'' exec sp__script_compile if (select count(*) from #out)=0 goto err_nrec -- now #out(line) contain cvs of selected lines update #out set line=''union select ''+line -- break inserts into small blocks because is faster select @n=count(*)/64+1 from #out set identity_insert #out on -- insert ''inserts'' insert #out(lno,line) select (r.row-1)*640+1,''insert into [''+@dst+'']'' from dbo.fn__range(1,@n,1) r -- insert ''insert'' fields insert #out(lno,line) select (r.row-1)*640+5,'' (''+@oflds+'')'' from dbo.fn__range(1,@n,1) r set identity_insert #out off update #out set line='' select ''+substring(line,14,4000) from #out o join dbo.fn__range(1,@n,1) r on o.lno=(r.row-1)*640+10 -- begin to out the script exec sp__script_template ''%safety%'' if not @where is null or not @top is null select @excludes=@excludes+''|where'' exec sp__script_template ''%before%'', @tokens=''%dst%|%flds%|%src%'', @v1=@dst,@v2=@oflds,@v3=@src, @opt=''print'', @excludes=@excludes --,@dbg=1 exec sp__print_table ''#out'' -- mix exec sp__script_template ''%after%'', @tokens=''%dst%|%flds%|%src%'', @v1=@dst,@v2=@oflds,@v3=@src, @opt=''print'', @excludes=@excludes -- ,@dbg=1 exec sp__printf ''\nsafe_skip:'' drop table #src drop table #out drop table #tpl drop table #tpl_sec goto ret -- =================================================================== errors == err_noo: exec @ret=sp__err ''no table found'',@proc goto ret err_nrec: exec @ret=sp__err ''no records found'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope generate inserts for @tbl if dest table has identity generate adeguate code Parameters @tbl name of table where select/insert data @where optional filter for rows @top optional top (@top) rows @opt options Options merge step into a middle #tbl for mixing operations The ukey is defined manually scramble apply scramble function to *chars fields noinc skip autoincrement column bincols:x|y convert columns x and y and ... into binary (0x545...) This is necessary in some cases where a nvarchar filed is used as binary container, because a special character block the copy&paste to&from clipboard '' select @ret=-1 ret: return @ret end -- sp__script_data' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_data: -- =============================================================== sp__script_db select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_db',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090914 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_db') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_db') with nowait goto skip_sp__script_db end if @ver>090914 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_db') with nowait goto skip_sp__script_db end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_db') with nowait if exists( select top 1 null from sys.objects where name='sp__script_db' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_db] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090914\s.zaglio: added nocollation v:090909\s.zaglio: create a script of all db with dependencies, users, roles, ext.prop t: exec sp__run_cmd ''del %temp%\%@@servername%_%db_name()%.sql /q'' exec sp__script_db exec sp__run_cmd ''type %temp%\%@@servername%_%db_name()%.sql'' exec sp__run_cmd ''del %temp%\%@@servername%_%db_name()%.sql /q /f'' -- exec sp__run_cmd ''dir %temp%\*.*'' -- exec sp__run_cmd ''del %temp%\*.* /q /s /f'' */ CREATE procedure [dbo].[sp__script_db] @srv nvarchar(100)=null,--the name of the source server @db nvarchar(100)=null,--the name of the source database @uid nvarchar(100)=null,--the login to the source server @pwd nvarchar(100)=null,--the password to the source server @out sysname=null, @dbg bit=0 as begin set nocount on if @srv is null select @srv=@@servername if @db is null select @db=db_name() declare @hr int, @filename nvarchar(100), @oserver int, @otransfer int, @errorobject int, @strcommand nvarchar(255), @strresult nvarchar(255), @errormessage nvarchar(2000), @strobjectname nvarchar(100), @slice int declare @tmp sysname exec sp__get_temp_dir @tmp out if right(@out,1)=''\'' select @out=left(@out,len(@out)-1) if not @out is null and right(@out,4)!=''.sql'' and @out!=''#src'' select @filename=@out else set @filename = @tmp select @filename=@filename+''\''+@srv+''_''+@db+''.sql'' if @dbg=1 exec sp__printf ''out to:%s'',@filename exec @hr = sp_oacreate ''sqldmo.sqlserver'', @oserver out if @hr=0 exec @hr = sp_oacreate ''sqldmo.transfer'', @otransfer out if @pwd is null or @uid is null begin --use a trusted connection if @hr=0 select @errormessage=''setting login to windows authentication on ''+@srv, @errorobject=@oserver if @hr=0 exec @hr = sp_oasetproperty @oserver, ''loginsecure'', 1 if @hr=0 select @errormessage=''logging in to the requested server using windows authentication on ''+@srv if @uid is null and @hr=0 exec @hr = sp_oamethod @oserver, ''connect'', null, @srv if @uid is not null and @hr=0 exec @hr = sp_oamethod @oserver, ''connect'', null, @srv ,@uid end else begin if @hr=0 select @errormessage = ''connecting to ''''''+@srv+ '''''' with user id ''''''+@uid+'''''''', @errorobject=@oserver if @hr=0 exec @hr = sp_oamethod @oserver, ''connect'', null, @srv , @uid , @pwd end if @hr=0 select @errorobject=@otransfer, @errormessage=''assigning values to parameters'' if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyallobjects'', 1 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copydata'', 0 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyschema'', 1 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyalldefaults'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyallobjects'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyallrules'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyallstoredprocedures'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyalltables'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyalluserdefineddatatypes'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyalltriggers'', 0 --if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''copyallviews'', 0 -- -- if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''dropobjectsfirst'', 0 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''includedependencies'', 1 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''includegroups'', 1 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''includelogins'', 1 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''includeusers'', 1 if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''includedb'', 1 -- sqldmo_script_type vars -- see: http://msdn.microsoft.com/en-us/library/aa225364(SQL.80).aspx -- see: http://msdn.microsoft.com/en-us/library/aa225398(SQL.80).aspx if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''scripttype'', 68 -- print 4|64 -- def|tofile if @hr=0 exec @hr = sp_oasetproperty @otransfer, ''script2type'', 12582918 -- print 4194304|4|2|8388608 -- ext.prop|unicode|nocollation select @strcommand = ''databases("'' + @db + ''").scripttransfer'' if @hr=0 begin create table #devnul (t ntext) insert into #devnul -- prevent output exec @hr = sp_oamethod @oserver, @strcommand, null, @otransfer, 2, @filename drop table #devnul end if @hr=0 select @errorobject=@oserver,@errormessage=''using method ''+@strcommand if @hr<>0 begin declare @source nvarchar(255), @description nvarchar(255), @helpfile nvarchar(255), @helpid int execute sp_oageterrorinfo @errorobject, @source output,@description output,@helpfile output,@helpid output select @errormessage=''error whilst ''+@errormessage+'', ''+@description raiserror (@errormessage,16,1) end exec sp_oadestroy @otransfer exec sp_oadestroy @oserver return @hr end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_db: -- ============================================================ sp__script_debug select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_debug',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130927 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_debug') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_debug') with nowait goto skip_sp__script_debug end if @ver>130927 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_debug') with nowait goto skip_sp__script_debug end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_debug') with nowait if exists( select top 1 null from sys.objects where name='sp__script_debug' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_debug] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:fast,debug,keyuboard,shortcut, v:130927\s.zaglio: better automation v:130922\s.zaglio: enable fast debug from ssms t:sp__script_debug ''select @@spid as spid,@@version ver,db_name() db'' t:sp__script_debug '''' */ CREATE proc sp__script_debug @script nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin -- no try because not useful with sp__err test for example -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @test_id int,@crlf nvarchar(4),@sql nvarchar(max) -- =========================================================== initialization == select @test_id=isnull(object_id(''tempdb..#test''),0),@crlf=crlf from fn__sym() -- print object_id(''tempdb..#test'') -- ======================================================== second params chk == if @script is null and @test_id=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == if not @script is null and @test_id!=0 begin drop proc #test exec sp__printf ''#test dropped'' select @test_id=0 end if @script='''' goto ret if @test_id!=0 exec #test else begin if not object_id(@script) is null select @script=''exec ''+@script if not object_id(left(@script,charindex('' '',@script)-1)) is null select @script=''exec ''+@script select @sql =''create proc #test''+@crlf +''as''+@crlf +''begin''+@crlf +''set nocount on;''+@crlf +@script+@crlf +''end'' begin try exec(@sql) exec sp__printf ''#test created'' exec #test end try begin catch exec sp__err null,''#test'',@opt=''ex'' end catch end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create or alter or delete or execute a proc #test with body @script Notes Normally I associate this sp to shortcut CTRL+9 (in memory of litmus test - test of nine in italian). Parameters [param] [desc] @opt (not used) @dbg (not used) Examples -- print help sp__script_debug -- init the debug sp__script_debug "select @@spid as spid,@@version ver,db_name() db" -- run it sp__script_debug -- drop #test sp__script_debug "" '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_debug' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_debug: -- ========================================================= sp__script_declares select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_declares',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130903 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_declares') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_declares') with nowait goto skip_sp__script_declares end if @ver>130903 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_declares') with nowait goto skip_sp__script_declares end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_declares') with nowait if exists( select top 1 null from sys.objects where name='sp__script_declares' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_declares] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script k:variable,table v:130903\s.zaglio:used fn__sql_normalize in place of fn__sql_simplify v:130521\s.zaglio:correction of help d:120508\s.zaglio:sp__script_vtable v:111124\s.zaglio:create declare of a variable table based on sql */ CREATE proc sp__script_declares @sql nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @sql is null goto help -- ============================================================== declaration == declare @tmp sysname create table #src(lno int identity,line nvarchar(4000)) -- =========================================================== initialization == select @tmp=''#''+replace(convert(sysname,newid()),''-'',''_''), @sql=dbo.fn__str_unquote(@sql,''[]'') -- ======================================================== second params chk == -- ===================================================================== body == if left(dbo.fn__sql_normalize(@sql,''sel''),7)=''select '' select @sql=''select top 0 * into ''+@tmp+'' from (''+@sql+'') a'' else if left(@sql,1)!=''#'' begin if object_id(@sql) is null goto err_nob select @sql=''select top 0 * into ''+@tmp+'' from [''+@sql+'']'' end if left(@sql,1)=''#'' begin if object_id(''tempdb..''+@sql) is null goto err_nob else select @tmp=@sql end insert #src(line) select ''declare @tmp table('' -- select * from fn__sql_def_cols(''sysobjects'','','',default) select @sql=@sql+'' insert #src(line) select '''' ''''+dbo.fn__flds_quotename(fld,default)+'''' ''''+def+sep from fn__sql_def_cols(''''''+@tmp+'''''','''','''',default) order by ord '' exec(@sql) insert #src(line) select '')'' exec sp__print_table ''#src'' drop table #src goto ret -- =================================================================== errors == err_nob: exec @ret=sp__err ''object not found'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope script declare of a variable table (todo: declare variables for fields) Parameters @sql table,view,#temp table or query to use @opt options (not used) Examples sp__script_declares "sysobjects" sp__script_declares "select name,xtype,crdate from sysobjects" '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_vtable' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_declares: -- ============================================================== sp__script_dep select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_dep',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110324 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_dep') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_dep') with nowait goto skip_sp__script_dep end if @ver>110324 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_dep') with nowait goto skip_sp__script_dep end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_dep') with nowait if exists( select top 1 null from sys.objects where name='sp__script_dep' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_dep] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:110324\s.zaglio: show also inverse list v:110315\s.zaglio: show dependencies of an object t:sp__script_dep ''sp__script_dep'' t:sp__script_dep ''tids'',@opt=''uses'' */ CREATE proc sp__script_dep @obj sysname = null, @level int = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == select @level=isnull(@level,1) -- ============================================================== declaration == declare @drop bit -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == if @obj is null or @level>1 goto help if object_id(''tempdb..#dep'') is null create table #dep( id int identity, uses bit, obj sysname, buildin sysname null, usr sysname null, comment sysname null, [level] int ) else select @drop=0 -- ===================================================================== body == -- sp__script_dep ''sp__script_dep'' if charindex(''|uses|'',@opt)=0 insert into #dep(uses,obj,buildin,usr,comment,[level]) select distinct 0 as uses, object_name(dep.depid) as require, convert(sysname,tag.val1) as buildin, convert(sysname,val2) as usr, convert(sysname,val3) as comment, 1 as [level] -- select top 10 * from sysdepends dep from sysdepends dep --sys.sql_dependencies cross apply fn__script_info(object_name(depid),''v'',default) tag where id=object_id(@obj) and tag.row=0 order by 1 else insert into #dep(uses,obj,buildin,usr,comment,[level]) select distinct 1 as uses, object_name(dep.id) as require, convert(sysname,tag.val1) as buildin, convert(sysname,val2) as usr, convert(sysname,val3) as comment, 1 as [level] -- select top 10 * from sysdepends dep from sysdepends dep --sys.sql_dependencies cross apply fn__script_info(object_name(depid),''v'',default) tag where depid=object_id(@obj) and tag.row=0 order by 1 if @drop is null begin select * from #dep order by id drop table #dep end goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope show dependencies of an object If table #dep exists, will be filled to be used by caller: create table #dep( id int identity, uses bit, obj sysname, buildin sysname null, usr sysname null, comment sysname null, [level] int ) Parameters @obj object name @level show more levels of dependencies (today only 1 level is admitted) @opt options uses show objects that uses @obj and not that depends Examples sp__script_dep ''''sp__script_dep'''' '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_dep' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_dep: -- ======================================================== sp__script_evolution select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_evolution',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130823 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_evolution') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_evolution') with nowait goto skip_sp__script_evolution end if @ver>130823 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_evolution') with nowait goto skip_sp__script_evolution end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_evolution') with nowait if exists( select top 1 null from sys.objects where name='sp__script_evolution' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_evolution] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:extract,data,version,history,project,chart,graphics v:130823\s.zaglio: extract data for a graphics of history of develop t:sp__script_evolution ''utility'',@dbg=1 */ CREATE proc sp__script_evolution @grp sysname = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @older_dt datetime,@newer_dt datetime,@days int declare @tags table(obj sysname, tag varchar(8), val1 sysname,val3 sysname) declare @nfo table(sdt sysname,dt datetime,comment nvarchar(max)) -- =========================================================== initialization == -- ======================================================== second params chk == if @grp is null goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- extract all version/release and group tags insert @tags select obj,tag,isnull(cast(val1 as sysname),''''),isnull(cast(val3 as sysname),'''') from fn__Script_info(default,''rvg'',default) -- remove objs of other groups than @grp delete tags from @tags tags join ( select a.obj from @tags a join @tags b on a.obj=b.obj and b.tag in (''v'',''r'') and isnumeric(cast(b.val1 as sysname))=1 where a.tag=''g'' and cast(a.val1 as sysname)!=@grp ) todel on todel.obj=tags.obj -- remove group and not tagged obj or not valid versions delete @tags where tag=''g'' or tag is null or isnumeric(val1)=0 or (isnumeric(val1)=1 and val1<''070101'') -- trim time update @tags set val1=left(val1,6) if @dbg>0 select *,isnumeric(val1) isnum from @tags order by isnumeric(val1) desc,val1 -- calculate ranges select @older_dt=convert(datetime,min(val1)), @newer_dt=convert(datetime,max(val1)) from @tags select @days=datediff(d,@older_dt,@newer_dt)+1 -- group info begin try insert @nfo select val1 as sdt, convert(datetime,val1,12) dt, ((select distinct obj+'':''+val3+'';'' from @tags where val1=a.val1 for xml path(''''),type).value(''.'',''nvarchar(max)'' )) from (select distinct val1 from @tags) a end try begin catch select ''bad date'' nfo,* from @tags where isdate(val1)=0 goto ret end catch if @dbg>0 select ''@nfo'' [@nfo],* from @nfo -- sp__script_evolution ''utility'',@dbg=1 -- show grouped history info select cast(y as sysname)+''-''+ substring(''jan feb mar apr may jun jul aug sep oct nov dec '',(m*4)-3,3) dt, sum(changes) changes, (select distinct comment from @nfo where year(dt)=y and month(dt)=m for xml path(''''),type).value(''.'',''nvarchar(max)'' ) comments from ( select year(b.dt) y,month(b.dt) m,isnull(changes,0) changes from ( select dt,count(*) changes from @nfo --order by convert(datetime,sdt,112) group by dt ) a right join ( select @older_dt+row-1 as dt from fn__range(1,@days,1) ) b on a.dt=b.dt ) a group by y,m order by y,m -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope extract data for a graphics of history of develop; can be used into Excel Parameters [param] [desc] @opt options @grp group name @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_evolution' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_evolution: -- ============================================================ sp__script_fkeys select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_fkeys',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_fkeys') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_fkeys') with nowait goto skip_sp__script_fkeys end if @ver>120117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_fkeys') with nowait goto skip_sp__script_fkeys end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_fkeys') with nowait if exists( select top 1 null from sys.objects where name='sp__script_fkeys' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_fkeys] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120117\s.zaglio: a small bug v:110406\s.zaglio: adapted to new form, removed #objs v:100919\s.zaglio: adapted to #objs v:100328\s.zaglio: adapted to new sp__script v:090813\s.zaglio: get fkeys script source s:http://blog.sqlauthority.com/2008/04/18/sql-server-generate-foreign-key-scripts-for-database/ t: create table test_fk1(id int primary key, v sysname) create table test_fk2(ref_id int, v sysname) alter table dbo.test_fk2 add constraint fk_test_fk2_test_fk1 foreign key(ref_id) references dbo.test_fk1(id) on update cascade on delete no action exec sp__script_fkeys ''test_fk1'' exec sp__script_fkeys ''test_fk2'' drop table test_fk2 drop table test_fk1 t:sp__script_fkeys ''%'' */ CREATE procedure [dbo].[sp__script_fkeys] @obj sysname=null, @opt sysname=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- 090813\s.zaglio: get fkeys script source if @obj is null goto help /* author : seenivasan this procedure is used for generating foreign key script. */ declare @src table (lno int identity primary key,line nvarchar(4000)) declare @fkname nvarchar(128) declare @fkcolumnname nvarchar(128) declare @pkcolumnname nvarchar(128) declare @fupdaterule int declare @fdeleterule int declare @fieldnames nvarchar(500) declare @n int create table #temp( pktable_qualifier nvarchar(128), pktable_owner nvarchar(128), pktable_name nvarchar(128), pkcolumn_name nvarchar(128), fktable_qualifier nvarchar(128), fktable_owner nvarchar(128), fktable_name nvarchar(128), fkcolumn_name nvarchar(128), key_seq int, update_rule int, delete_rule int, fk_name nvarchar(128), pk_name nvarchar(128), deferrability int) declare @objs table (obj sysname) if charindex(''%'',@obj)>0 insert @objs select [name] from sysobjects where [name] like @obj and xtype=''u'' else insert @objs select parsename(@obj,1) declare ttablenames cursor local for select obj from @objs open ttablenames fetch next from ttablenames into @obj while @@fetch_status = 0 begin insert #temp exec dbo.sp_fkeys @obj fetch next from ttablenames into @obj end -- while close ttablenames deallocate ttablenames set @fieldnames = '''' set @obj = '''' select distinct fk_name as fkname,fktable_name as ftname, @fieldnames as ftfields,pktable_name as stname, @fieldnames as stfields,@fieldnames as fktype into #temp1 from #temp order by fk_name,fktable_name,pktable_name declare fk_cusror cursor for select distinct fkname from #temp1 open fk_cusror fetch from fk_cusror into @fkname while @@fetch_status = 0 begin declare fk_fields_cusror cursor for select fkcolumn_name,pkcolumn_name,update_rule,delete_rule from #temp where fk_name = @fkname order by key_seq open fk_fields_cusror fetch from fk_fields_cusror into @fkcolumnname,@pkcolumnname, @fupdaterule,@fdeleterule while @@fetch_status = 0 begin update #temp1 set ftfields = case when len(isnull(ftfields,'''')) = 0 then ''[''+@fkcolumnname+'']'' else ftfields+'',[''+@fkcolumnname+'']'' end where fkname = @fkname update #temp1 set stfields = case when len(isnull(stfields,'''')) = 0 then ''[''+@pkcolumnname+'']'' else stfields +'',[''+@pkcolumnname+'']'' end where fkname = @fkname fetch next from fk_fields_cusror into @fkcolumnname,@pkcolumnname, @fupdaterule,@fdeleterule end -- fk_fields update #temp1 set fktype = case when @fupdaterule = 0 then fktype + '' on update cascade'' else fktype end where fkname = @fkname update #temp1 set fktype = case when @fdeleterule = 0 then fktype + '' on delete cascade'' else fktype end where fkname = @fkname close fk_fields_cusror deallocate fk_fields_cusror fetch next from fk_cusror into @fkname end -- fk_cursor close fk_cusror deallocate fk_cusror if exists(select null from #temp1) insert into @src(line) select ''go'' insert into @src(line) select ''alter table [dbo].[''+ftname+''] with nocheck add constraint [''+fkname+''] foreign key (''+ftfields+'') references [''+stname+''] (''+stfields+'') ''+fktype from #temp1 if object_id(''tempdb..#src'') is null select line from @src order by lno else insert #src(line) select line from @src order by lno goto ret -- ===================================================================== help == help: exec sp__usage @proc select @ret=-1 ret: set nocount off return @ret end -- sp__Script_fkeys' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_fkeys: -- ============================================================ sp__script_group select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_group',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131126 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_group') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_group') with nowait goto skip_sp__script_group end if @ver>131126 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_group') with nowait goto skip_sp__script_group end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_group') with nowait if exists( select top 1 null from sys.objects where name='sp__script_group' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_group] begin try exec dbo.sp_executesql @statement = N'/* Leave this unchanged doe MS compatibility l:see LICENSE file g:utility,script v:131126\s.zaglio: added recache option v:131027\s.zaglio: added cache for slow computers v:130730.1230,130729,130726,130725,130724,130723,130722,130719\s.zaglio: restructuring r:130703;130701\s.zaglio: removed prefix; removed old unused code;moving code sp__script r:130613\s.zaglio: deprecated html out and moved index to ... r:130610\s.zaglio: integration with fn__script_group_select v:130417;130127\s.zaglio: added author filter and script of obj|obj|...;added %latests_objs% v:121229;121218\s.zaglio: replaced %now% with %dt% and added %db%;around problem of "\" v:121108\s.zaglio: searching bug of \{space} (found into sp__script) v:121004.1614\s.zaglio: exclude _old objs and used sp__deprecated v:120924;120921\s.zaglio: around error management;added prefix opt v:120920\s.zaglio: exec setup also at end and used try-catch v:120907.1500\s.zaglio: deprecated tag X and used postfix _%grp%_setup r:120907\s.zaglio: added chk if sp__script_store,grp,%_setup are in R v:120827\s.zaglio: added app_name test and forced convert to db 90 v:120823.1000;120731\s.zaglio: added nochk option and better tests;test of #script_results v:120727\s.zaglio: added errors check and script repeat v:120725.1557;120724\s.zaglio: spring test and done;messaging and new tag X v:120516.1841\s.zaglio: adapted to new fn__script_sysobjs & fn__script_sign v:120510;120201\s.zaglio: a bug near deprecated "null" names;fn__sym before others v:111230;111229\s.zaglio: adapted to new sp__script_template;adapting to new sp__script_template r:111228;111223\s.zaglio: added support for multi &grp;adapting to new sp__script_template v:111205;111111\s.zaglio: added script of direct objects;excluded deprecated from group v:111007;110916\s.zaglio: added sortable func to index.html;adapted to new fn__buildin v:110824;110704\s.zaglio: adapted to new sp__script_template;specified log_ddl upgrade version v:110701.1848;110630;110629\s.zaglio: added upgrade of log_ddl;re-profiling;used fn__sysobjects v:110628\s.zaglio: added deprecated management and script of trigger db v:110623;110621\s.zaglio: better comment position;a small bug near drop and more info v:110620;110615\s.zaglio: done 3rd review with versioning;readded out to file/s and html r:110614;110603\s.zaglio: added versioning;added integration with history v:110509;110406\s.zaglio: added print obj in regen...;adapted to new sp__script & C. v:100919.1005\s.zaglio: a bug near html creations v:100919.1001\s.zaglio: script ordered by name desc v:100919\s.zaglio: added note about script of fkeys v:100905;100724\s.zaglio: added origin db check;a bug near html generation v:100718100612\s.zaglio: added check of origin db;added more examples v:100523;100501\s.zaglio: renamed option hidx to index;added last chg column on html table v:100418.2200\s.zaglio: use of fn__script_info and added hidx v:100411\s.zaglio: added * to collect tables&views v:100405;100403\s.zaglio: done & tested;adapted to 3rd remake of sp__script v:100328;091126\s.zaglio: adapted to new version of sp__Script;added list of groups in help v:091018\s.zaglio: remake of old sp__script_group to separate from use of table t:sp__script_group ''UTILITY@s.zaglio'',@dbg=2,@exclude=''fn__word%'' t:sp__script_group ''utility'',@out=''%temp%\%grp%_%t'',@dbg=2 -- single file out t:sp__script_group ''utility'',@out=''%temp%\%obj%_%t'',@dbg=2 -- multi file out t:sp__script_group ''fn__str_table|fn__str_at'' t:sp_script_utility @out=''%temp%\%grp%.sql'',@dbg=1 */ CREATE proc [dbo].[sp__script_group] @grp nvarchar(4000) = null, @out nvarchar(max) = null out, @exclude nvarchar(4000) = null, @include nvarchar(4000) = null, @opt sysname = null, @dbg int = 0 as begin try set nocount on declare @proc sysname,@ret int, @e_msg nvarchar(4000),@e_p1 sysname,@e_p2 sysname, @t datetime,@i int,@aut sysname -- derived parameter select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(coalesce(@opt,''''),''|''), @t=getdate() -- ================================================================ param chk == if @grp is null goto help -- ============================================================= declarations == declare @n int,@obj sysname,@sql nvarchar(max),@isql nvarchar(4000), @src nvarchar(max), @type nvarchar(2),@tmp sysname,@var_id int,@src_id int, @db sysname,@xt nvarchar(2), @go sysname,@ver sysname, @dothtm nvarchar(32),@crlf nvarchar(2), @grp_sep nvarchar(4),@obj_sep nvarchar(4), @grp_util sysname,@db_util sysname, @tgs varchar(4), -- tags of objs to consider, @tag nvarchar(8), @tpl sysname, -- name of template @ver_grp numeric(10,4), -- max version of utilities @latests_objs nvarchar(4000), -- max ver:obj,obj,obj,... @grp_setup sysname, -- like for name of group setup object @drop nvarchar(512), @opt_script sysname, @tmp_script_group_cache_id int, @key varbinary(16), -- options @bin bit,@recache bit, @end_declare bit if charindex(''|'',@grp)>0 goto script_objs declare @objs table( obj_id int null, obj sysname, xt nvarchar(2) null, tag nvarchar(16) default(''v''), aut sysname null, -- info.val2 ver nvarchar(16) null, -- info.val1 [des] sysname null, -- info.val3 grp1 sysname null default(''''), grp2 sysname null default(''''), grp3 sysname null default(''''), core bit default(0), -- basic obj used to define others [drop] nvarchar(512) null, ord int, match bit ) -- =========================================================== check in cache == -- drop table tmp_script_group_cache if object_id(''tmp_script_group_cache'') is null create table tmp_script_group_cache( dt datetime not null, id int identity not null, [key] varbinary(16) not null, latests_objs nvarchar(320) not null, -- print 450-128=322 [out] nvarchar(max) not null, constraint pk_tmp_script_group primary key (id) ) select @key=hashbytes(''md5'',@grp+''|''+isnull(@include,'''') +''|''+isnull(@exclude,'''')+ +@opt) select @tmp_script_group_cache_id=isnull(object_id(''tmp_script_group_cache''),0) if @tmp_script_group_cache_id!=0 -- purge data older than one year (not necessary but more safest) delete from tmp_script_group_cache where dt0 select @aut=substring(@grp,@i+1,128),@grp=left(@grp,@i-1) insert into @objs( obj_id,obj,xt,tag,aut,ver,[des],grp1,grp2,grp3,core,[drop],ord,match ) select obj_id,obj,xt,tag,aut,ver,[des],grp1,grp2,grp3,core,[drop],ord,match from fn__script_group_select(@grp,@exclude,@include,default,default) if @@rowcount=0 raiserror(''no objects for this group'',16,1) -- check for bad headers select @exclude=null select @exclude=isnull(@exclude+'','','''')+obj from (select distinct obj from @objs where isnumeric(ver)=0) a if isnull(@exclude,'''')!='''' raiserror(''this objects has bad version: %s'',16,1,@exclude) -- update version for non versioned objects update @objs set ver=dbo.fn__script_buildin(getdate(),1,'''','''') where ver is null -- teorically tables if @dbg>0 exec sp__elapsed @t out,''after obj list'' if @dbg>1 select * from @objs order by core desc,tag,ord,obj if @dbg=0 and exists( select top 1 null from @objs nfo where cast(tag as nchar)=''R'' and ( object_name(obj_id) in (@proc,''sp__script_store'',''sp__script'') or object_name(obj_id) like ''%''+@grp+''_setup'' ) ) begin select @e_msg=''"sp__script_group" or "sp__script_store" '' +''or "sp__script" '' +''or "group setup object" are in R state'' raiserror(@e_msg,16,1) end -- ============================================================== #temp table == select @var_id=isnull(object_id(''tempdb..#vars''),0), @src_id=isnull(object_id(''tempdb..#src''),0) create table #tpl (lno int identity,line nvarchar(4000)) create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) create table #tpl_cpl(tpl binary(20),section sysname,y1 int,y2 int) create index #ix_tpl_cpl on #tpl_cpl(tpl,section) if @var_id=0 create table #vars (id nvarchar(16),value nvarchar(4000)) if @src_id=0 create table #src (lno int identity,line nvarchar(4000)) -- todo: test run, checking if is in R state by other user -- inside dbg /* exec('' create proc #chk as if exists(select null from #src where right(line,2)=''''\ '''') exec sp__printf ''''bug!!!'''' '') */ -- =============================================================== templates == -- NB: chk of version of utility is limitating if outside -- better use fn__Script_sign inside sp. /* templates dependencies - %scr_header% - %disable_tracer% - %tmp_deprecated% - for each core object - %obj_core_chk% - %skip_obj% - for each other objects - %obj_ver_chk% -- from sp__script - %skip_obj% - %enable_tracer% - %scr_footer% */ exec sp__script_templates ''group'' if @dbg>0 exec sp__elapsed @t out,''after templates init'' -- ===================================================================== init == exec sp__get_temp_dir @tmp out select -- @out=nullif(@out,''''), because used to return the entire script @grp_setup=(select top 1 name from sys.objects where type=''P'' and name like ''%''+@grp+''_setup'' ), @grp_util=''utility'', @db_util=''utility'', @tgs=''rv'', @grp_sep='','', @obj_sep=''|'', @crlf=crlf, @db=db_name(), @go=''go'', @dothtm=''.htm'', @bin=charindex(''|bin|'',@opt), @recache=charindex(''|recache|'',@opt), @out=replace( replace( replace(@out,''%temp%'',@tmp), ''%grp%'',replace(@grp,'','',''_'') ), ''%t'',dbo.fn__format(getdate(),''YYYYMMDD_HHMMSS'',default) ) +case when @out='''' or @out like ''%.sql'' then '''' else ''.sql'' end from fn__sym() -- check that every R,V tag has a correct numeric version select @latests_objs=null -- list of bad versions select @latests_objs=isnull(@latests_objs+@crlf+obj+'':''+ver, obj+'':''+ver ) from @objs where tag in (''r'',''v'') and not (ver like ''[0-9][0-9][0-9][0-9][0-9][0-9]'' -- yymmdd or --yymmdd.hhmm or ver like ''[0-9][0-9][0-9][0-9][0-9][0-9].[0-9][0-9][0-9][0-9]'') if not @latests_objs is null begin exec sp__printf ''%s'',@latests_objs raiserror(''above list of objects has bad version'',16,1) end -- this is necessary due a bug or an optimization in the engine declare @vers table(obj sysname,ver numeric(10,4)) insert @vers(obj,ver) select obj,cast(ver as numeric(10,4)) -- this in the where causes error from @objs where tag in (''r'',''v'') -- calculate max group version select @ver_grp=max(cast(ver as numeric(10,4))) from @vers -- sp__script_group ''utility'' -- list of latests objects select @latests_objs=isnull(@latests_objs+'',''+obj, replace(cast(@ver_grp as sysname), ''.0000'', '''' )+'':''+obj ) from @vers where ver=@ver_grp -- ================================================ check if already in cache == if @tmp_script_group_cache_id!=0 and @recache=0 begin select @src=null select top 1 @src=[out] from tmp_script_group_cache where [key]=@key and latests_objs=@latests_objs if not @src is null begin -- resplit into #src insert #src(line) select line from fn__ntext_to_lines(@src,0) if @out='''' select @out=@src if @dbg>0 exec sp__printf ''-- get script from cache'' goto out_to_cached end -- test cache end -- if cache enabled -- =============================================================== init macro == insert #vars select ''%svr%'',@@servername union select ''%grp%'',@grp union select ''%grp_setup%'',@grp_setup union select ''%db_util%'',@db_util union select ''%latests_objs%'',@latests_objs union -- markers select ''%obj%'',null union select ''%ver%'',null union select ''%aut%'',null union select ''%drop%'',null -- ======================================================== select all object == -- check invalid deprecated tags if exists( select top 1 null from @objs nfo where nfo.tag=''d'' and isnumeric(convert(sysname,grp1))=0 ) exec sp__printf ''-- W A R N I N G : some invalid deprecated tags'' -- =================================================================== header == if @grp!=@db_util select @exclude=''utility'' else select @exclude=''other'' -- expand proc into section exec sp__script_template ''%script_catch_definition%'', ''%script_catch_implementation%'' update #tpl_sec set line=replace(line,'''''''','''''''''''') exec sp__script_template ''%scr_header%'',@excludes=@exclude -- ============================================================= uninst trace == if @grp in (@grp_util) exec sp__script_template ''%disable_tracer%'' if @dbg>0 exec sp__elapsed @t out,''after header scripting'' -- =================================================== loop into core objects == select @opt_script=''upgrade|nodecl|nohdr|nofot'' if not @out is null select @opt_script=@opt_script+''|tofile'' if @grp in (@grp_util) begin exec sp__printframe ''core objects has different version check'',@out=''#src'' declare cs_core cursor local fast_forward for select grp.obj,grp.xt,grp.tag,grp.[drop] from @objs grp where grp.core=1 and grp.tag in (''r'',''v'') order by grp.ord,grp.obj open cs_core while 1=1 begin fetch next from cs_core into @obj,@xt,@tag,@drop if @@fetch_status!=0 break select @ver=dbo.fn__script_sign(@obj,1) update #vars set value=case id when ''%obj%'' then @obj when ''%ver%'' then @ver when ''%drop%'' then @drop end where id in (''%obj%'',''%ver%'',''%drop%'') insert into #src(line) select '''' union select ''-- ''+dbo.fn__format(@obj,''=< '',77) if @obj!=''fn__script_sign'' exec sp__script_template ''%obj_core_chk%'' else begin insert #src(line) select ''raiserror(''''drop&create "fn__script_sign"'''',10,1)'' insert #src(line) select token from dbo.fn__str_table_fast(@drop,@crlf) end if @dbg=1 exec sp__printf ''scripting:%s, ver:%s'',@obj,@ver -- ########################## -- ## -- ## dump CORE obj into #src -- ## -- ######################################################## exec sp__script @obj,@opt=@opt_script if @obj!=''fn__script_sign'' exec sp__script_template ''%skip_obj%'',@excludes=''setup'' end -- while close cs_core deallocate cs_core end -- script 1st core objects for utility if @dbg>0 exec sp__elapsed @t out,''after core scripting'' -- =============================================================== deprecated == exec sp__printframe ''remove deprecated'',@out=''#src'' insert into #src(line) select ''exec sp__deprecate ''''''+[des]+'''''',''+ver from @objs where tag in (''d'') order by case xt when ''TD'' then 0 else 1 end, ord,obj if @dbg>0 exec sp__elapsed @t out,''after deprecated scripting'' -- ================================================== loop into objects group == exec sp__printframe ''group objects'',@out=''#src'' select @opt_Script=''upgrade|nodecl|nofot'' if not @out is null select @opt_script=@opt_script+''|tofile'' declare cs cursor local fast_forward for select grp.obj,grp.xt,grp.tag,grp.ver,grp.aut,grp.[drop] from @objs grp where tag in (''r'',''v'') and grp.core=0 order by grp.ord,grp.obj open cs while 1=1 begin fetch next from cs into @obj,@xt,@tag,@ver,@aut,@drop if @@fetch_status!=0 break update #vars set value=case id when ''%obj%'' then @obj when ''%ver%'' then @ver when ''%aut%'' then @aut when ''%drop%'' then @drop end where id in (''%obj%'',''%ver%'',''%aut%'',''%drop%'') insert into #src(line) select ''-- ''+dbo.fn__format(@obj,''=< '',77) if @dbg>0 exec sp__printf ''scripting:%s, ver:%s, aut:%s'',@obj,@ver,@aut -- ########################## -- ## -- ## dump group obj into #src -- ## -- ######################################################## exec sp__script @obj,@opt=@opt_Script -- exec #chk if @xt=''u'' exec sp__script_fkeys @obj -- grp obj footer select @tmp=case when @obj=@grp_setup then null else ''setup'' end exec sp__script_template ''%skip_obj%'',@excludes=@tmp end -- while object close cs deallocate cs if @dbg>0 exec sp__elapsed @t out,''after obj scripting'' -- ============================================================= uninst trace == if @grp in (@grp_util) exec sp__script_template ''%enable_tracer%'' -- =================================================================== footer == if @grp_setup is null select @exclude=isnull(@exclude,'''')+''setup'' exec sp__script_template ''%scr_footer%'', @tokens=''%grp_setup%'',@v1=@grp_setup, @excludes=@exclude if @dbg>0 exec sp__elapsed @t out,''after footer scripting'' -- ======================================================= out to single file == out_to: if @bin=1 exec sp__script_compress select @src= stuff( (select @crlf + line from #src order by lno for xml path(''''), type ).value(''(./text())[1]'',''nvarchar(max)'') , 1, len(@crlf), '''') -- if cache enabled if @tmp_script_group_cache_id!=0 begin update tmp_script_group_cache set [out]=@src where [key]=@key if @@rowcount=0 insert tmp_script_group_cache(dt,[key],latests_objs,[out]) select getdate(),@key,@latests_objs,@src end out_to_cached: if @src_id=0 begin if @out is null exec sp__print_table ''#src'' else begin if @dbg>0 exec sp__printf ''out to %s'',@out if @dbg=2 begin exec sp__print_table ''#src'' end else exec sp__file_write_stream @out if @dbg>0 exec sp__elapsed @t out,''after out to file'' end end -- out -- out to variable if @out='''' select @out=@src dispose: if @src_id=0 drop table #src if @var_id=0 drop table #vars goto ret -- ==================================================== script direct objects == script_objs: -- t:sp__script_group ''fn_str_at|fn__str_at|sp__chknulls'' -- t:sp__script_group ''fn__str_at|sp__chknulls'' declare cs cursor local for select token from dbo.fn__str_table(@grp,''|'') open cs while 1=1 begin fetch next from cs into @obj if @@fetch_status!=0 break exec @ret=sp__script @obj,@opt=''upgrade'' if @ret!=0 goto ret end -- cursor cs close cs deallocate cs goto out_to -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope script a group of objects by category see below for more info Parameters #src (optional) fill the caller table #vars (optional) used to fill some specials macro (as %license%) @grp single group to script can postfix with @AUTHOR to filter only objects where author of last version is AUTHOR; * the group is identified by tag G: * tag G support multiple groups separated by comma (",") * if contain a %, select names instead of group * if contain *, select also tables (with idxs,fkeys,trs) * SYS group, script S objects from fn__script_sysobjs * obj1|obj2|... direct script only obj1,obj2,... calling sp__script with opt upgrade @out * if passed an empty string, return the script * can be a path where out a single file (extension is .sql) %grp% will be replaced with group name and create a unique file %t will be replaced with YYMMDD_HHMMSS %temp% will be replaced with windows user temp directory @opt options bin return results as compressed binary string recache ignore cached version and re-script then re-cache @dbg 1 list selected objects and exit 2 print and do not out to files @exclude is a "like" expression for post exclusion of objects @include is a "like" expression for pre inclusion of objects Notes * an object that end with group name and "_setup", is considered the setup store procedure of the group, scripted 1st and executed immediatelly * if sp__script_store and sp__script_group are in R tag, cannot script * if object "%_%groupname%_setup" is in R, scripting is aborted Examples -- normal use exec sp__script_group ''''utility'''' -- replace macros create table #vars (id nvarchar(16),value nvarchar(4000)) insert #vars select ''''%license%'''',''''test replacements'''' exec sp__script_group ''''script'''' drop table #vars ########################## ## ## SCRIPT GROUP STEPS ## ================== ## ## if script to console or into single file: ## drop deprecated objects ## check version ## drop object ## re-create ## ## is script "utility" group: ## if exists uninstall db trigger ## eventually re-create scripting core objects ## drop deprecated objects ## check version ## drop object ## re-create ## if exists install db trigger and upgrade if necessary ## ######################################################## '' select val1 as grp from fn__script_info(null,''g'',0) where not val1 is null union select val2 from fn__script_info(null,''g'',0) where not val2 is null union select val3 from fn__script_info(null,''g'',0) where not val3 is null order by 1 select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_group' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_group: -- ===================================================== sp__script_group_tofile select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_group_tofile',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=151107 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_group_tofile') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_group_tofile') with nowait goto skip_sp__script_group_tofile end if @ver>151107 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_group_tofile') with nowait goto skip_sp__script_group_tofile end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_group_tofile') with nowait if exists( select top 1 null from sys.objects where name='sp__script_group_tofile' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_group_tofile] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:each,object,single,file,one,into v:151107\s.zaglio: better dbg info v:130903\s.zaglio: renamed group list to index.txt r:130902\s.zaglio: added group list r:130830,130829,130824\s.zaglio: script each object of a group into file d:130824\s.zaglio:sp__script_tofile t:sp__script_group_tofile ''utility@s.zaglio'',''%temp%\utility'',@dbg=1 t:sp__script_group_tofile ''sp__script_declares'',''%temp%\utility'',@dbg=1 */ CREATE proc sp__script_group_tofile @grp nvarchar(4000) = null, @out nvarchar(1024) = null, @exclude nvarchar(4000) = null, @include nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @i int,@aut sysname,@src_id int,@obj sysname,@xt nvarchar(2), @tag nvarchar(8),@ver sysname,@drop nvarchar(512),@ext sysname, @temp nvarchar(512),@path nvarchar(1024),@n int, @psep nchar(1),@cmd nvarchar(1024),@pext int,@pdir int, @fmt sysname,@list_filename nvarchar(1024),@cr nchar(1),@lf nchar(1), -- option @lo bit, @end_declare bit if @src_id is null create table #src (lno int identity,line nvarchar(4000)) -- =========================================================== initialization == exec sp__get_temp_dir @temp out select @psep=psep, @grp=nullif(@grp,''''), @ext=''.sql'', @out=nullif(replace(@out,''%temp%'',@temp),''''), @cr=cr,@lf=lf, -- options @lo=charindex(''|lo|'',@opt) from fn__sym() -- ======================================================== second params chk == if @grp is null goto help select @pext=dbo.fn__charindex(''.'',@out,-1), @pdir=dbo.fn__charindex(@psep,@out,-1) if @pext>0 select @ext='''' if @pext>@pdir raiserror(''@out must be a path ending with %s'',16,1,@psep) if right(@out,1)!=@psep select @out=@out+''\'' -- ========================================================= get objects list == -- normalize objects list if given select @grp=replace(replace(@grp,@lf,@cr),@cr+@cr,@cr) select @grp=replace(@grp,@cr,''|'') -- extract author to filter, if given select @i=charindex(''@'',@grp) if @i>0 select @aut=substring(@grp,@i+1,128),@grp=left(@grp,@i-1) -- =============================================================== #tbls init == select top 0 * into #objs_list from fn__script_group_select(default,default,default,default,default) -- temp table for index file select top 0 -- identity(int,1,1) lno, obj,tag,ver,aut,des into #group_file_list from #objs_list -- ===================================================================== body == insert into #objs_list select * from fn__script_group_select(@grp,@exclude,@include,''@''+@aut,default) -- if no grp objects, test for single object if @@rowcount=0 and not object_id(@grp) is null begin if @dbg>0 exec sp__printf ''adding single object, keeping directory'' insert into #objs_list select g.* from fn__script_group_select(default,@exclude,@include,''@''+@aut,default) g cross apply fn__str_table_fast(@grp,''|'') objs where obj like objs.token end else -- found grp''s objects begin -- register info about group (now is in the name:@grp.csv) -- insert #group_file_list(obj,tag,ver,aut,des) select @grp,'''','''','''','''' -- drop target directory if exists if not @out is null begin select @cmd=''rmdir /s /q "''+@out+''"'' exec xp_cmdshell @cmd,no_output end end if not @out is null begin select @list_filename=@out+@grp+''.csv'' -- create target directory select @cmd=''mkdir "''+@out+''"'' exec xp_cmdshell @cmd,no_output end -- ======================================================= create/update list == -- reload file if exists if not @out is null begin if @dbg>0 exec sp__printf ''list to: %s'',@list_filename exec xp_fileexist @list_filename, @i output if @i!=0 exec sp__csv_import @list_filename,''#group_file_list'',@opt=''noh'' if @dbg>0 select @n=count(*) from #group_file_list end -- update/add released/versioned update gl set ver=ol.ver, aut=ol.aut, des=ol.des from #group_file_list gl join #objs_list ol on gl.obj=ol.obj and gl.tag=ol.tag if @dbg>0 select @n=@@rowcount insert #group_file_list(obj,tag,ver,aut,des) select ol.obj,ol.tag,ol.ver,ol.aut,ol.des from #group_file_list gl right join #objs_list ol on gl.obj=ol.obj and gl.tag=ol.tag where ol.tag in (''r'',''v'') and gl.obj is null if @dbg>0 select @n=@@rowcount -- update/add deprecated update gl set ver=ol.ver, aut=ol.aut, des=ol.des from #objs_list ol join #group_file_list gl on gl.obj=ol.des and gl.tag=ol.tag where ol.tag in (''d'') if @dbg>0 select @n=@@rowcount insert #group_file_list(obj,tag,ver,aut,des) select distinct ol.des,ol.tag,ol.ver,ol.aut,''in ''+ol.obj from #objs_list ol left join #group_file_list gl on gl.obj=ol.des and gl.tag=ol.tag where ol.tag in (''d'') and gl.obj is null if @dbg>0 select @n=@@rowcount -- print list if no to out-put if @out is null begin exec sp__select_astext ''#group_file_list'' goto ret end -- save list to file if 0=(select count(*) from #group_file_list) raiserror(''generating group file list'',16,1) exec sp__csv_export ''#group_file_list'',@list_filename,@opt=''noh'' if @lo=1 goto dispose -- ========================================= loop into list, script and store == declare cs cursor local fast_forward for select grp.obj,grp.xt,grp.tag,grp.ver,grp.aut,grp.[drop] from #objs_list grp where tag in (''r'',''v'') order by grp.ord,grp.obj open cs while 1=1 begin fetch next from cs into @obj,@xt,@tag,@ver,@aut,@drop if @@fetch_status!=0 break -- refine path select @path=@out+@obj+@ext if @dbg>1 exec sp__printf ''to script obj:%s(%s) ver:%s aut:%s'',@obj,@xt,@ver,@aut else begin truncate table #src exec @ret=sp__script @obj select @n=count(*) from #src if @dbg>0 exec sp__printf ''scripting obj:%s(%s) ver:%s aut:%s lines:%d to:%s'', @obj,@xt,@ver,@aut,@n,@path if @ret=0 exec @ret=sp__file_write_stream @path,@fmt=@fmt if @ret!=0 goto ret -- sp has written its error end end -- while close cs deallocate cs -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope script each object of a group into a single file Notes - a file index.txt is created and populated with the list of versions in CSV format: obj,tag,version,author,last comment - when single objects are scripted, the content of directory is kept and the list updated Parameters [param] [desc] @grp group name with optional prefix @author or list of objects separated by | or CR/LF @out destination path (a directory where put obj_name.sql and index.txt) if null index.txt is shown to console to be used by sp__upgrade @opt options lo list only, fill #objs_list without store files @dbg 1=show execution info 2=show objects to script without script and save to file 3=more up ... Examples sp__script_group_tofile ''''utility@s.zaglio'''',''''%temp%\utility'''' '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_group_tofile' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_group_tofile: -- ========================================================== sp__script_history select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_history',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140108 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_history') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_history') with nowait goto skip_sp__script_history end if @ver>140108 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_history') with nowait goto skip_sp__script_history end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_history') with nowait if exists( select top 1 null from sys.objects where name='sp__script_history' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_history] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:140108\s.zaglio: svr_id->srv_id r:120521\s.zaglio: added script header as -- or multi comment v:120517\s.zaglio: adapted to new fn__script_sysobjs v:120514\s.zaglio: added store of generic sql that begin with exec v:120509\s.zaglio: added store of generic sql r:120508\s.zaglio: adding store of generic sql r:120507\s.zaglio: added drop of objects and exists test on more crucial tables and index r:120504\s.zaglio: problem of drop fun X->create syn X r:120503\s.zaglio: introducing user in @obj to filter my objs v:120213\s.zaglio: adapted to new structures and fn__script_events r:120208\s.zaglio: adapting to new structures v:120206\s.zaglio: added usr column v:120126\s.zaglio: added top 100 v:110830\s.zaglio: better help v:110624\s.zaglio: restyling of output and removed rev from scripting v:110622\s.zaglio: restyling of output r:110621\s.zaglio: fine filter on alter for non table objects r:110603\s.zaglio: added exclude r:110511\s.zaglio: added >= date r:110510\s.zaglio: generate script for historicized objects t:sp__Script_history ''-60\\wsj\tempsa'',@dbg=2 */ CREATE proc sp__script_history @what nvarchar(max) = null, @list sysname = null, @grp sysname = null, @opt sysname = null, @dbg int = null as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == declare @top int select @top=100 if @what is null or object_id(''log_ddl'') is null goto help -- ============================================================== declaration == declare @sql nvarchar(4000),@cond nvarchar(32), @id int,@dt datetime,@evot sysname, @tmp sysname,@sdt sysname,@usr sysname, @obj sysname, @obj_id sysname,@ev sysname, @drop bit, -- option @i int, -- index @iwhat sysname, -- inside truncated @what @crlf nvarchar(2), @lbl sysname declare @excludes table(obj sysname) -- insert before here -- @end_declare bit if object_id(''tempdb..#src'') is null create table #src(lno int identity,line nvarchar(4000)) create table #objs( srv_id int, [db_id] int, id int, [name] sysname, [rel] sysname, [dt] datetime, ev sysname, evot sysname, -- event object type [type] nvarchar(3) null, usr sysname null, uinfo sysname null, next_ev sysname null, next_evot sysname null ) alter table #objs add [sql] nvarchar(max) -- =========================================================== initialization == select @drop=1-charindex(''|nodrop|'',@opt), @usr='''', @crlf=crlf from fn__sym() while (left(ltrim(@what),len(@crlf))=@crlf) select @what=substring(rtrim(ltrim(@what)),len(@crlf)+1,len(@what)) select @iwhat=left(ltrim(@what),128) -- ======================================================== second params chk == if left(@iwhat,1)=''-'' begin select @usr=''\\''+dbo.fn__str_at(@iwhat,''\\'',2) select @i=cast(dbo.fn__str_at(@iwhat,''\\'',1) as int) select @dt=getdate()+@i select @iwhat=convert(sysname,@dt,126)+@usr end -- ===================================================================== body == if left(@iwhat,7)=''insert '' or left(@iwhat,3)=''if '' or left(@iwhat,5)=''exec '' or left(@iwhat,3)=''-- '' or left(@iwhat,3)=''/* '' begin -- select * from fn__script_sysobjs((select ev from tids)) exec sp__script_store @et=''insert_data'',@obj=''data_script'', @sql=@what,@dbg=@dbg goto ret end insert @excludes(obj) select token from dbo.fn__str_table(replace(replace(@list,'','',''|''),'';'',''|''),''|'') insert #src(line) select ''/''+replicate(''*'',79) if patindex(''____-__-__T__:__:__.___'',replace(@iwhat,'' '',''T''))>0 or patindex(''____-__-__T__:__:__.___\\%'',replace(@iwhat,'' '',''T''))>0 begin if object_id(''fn__script_trace'') is null goto err_trc select @sdt=replace(dbo.fn__str_at(@iwhat,''\\'',1),'' '',''T''), @usr=''\\''+dbo.fn__str_at(@iwhat,''\\'',2) if @usr='''' select @usr=''%'' insert #src(line) select ''** unScript from ''+@iwhat -- sp__script_history ''2012-02-08 14:37:14.057'' -- drop table #objs -- select * from fn__script_trace(default,default,default) -- drop table #test -- declare @sql nvarchar(max),@iwhat sysname select @iwhat=''2011-04-15T16:00:33.920'' -- truncate table #objs -- declare @sql nvarchar(4000),@iwhat sysname select @iwhat=''2011-06-20T18:04:57.800'' -- declare @iwhat sysname select @iwhat=''2012-02-08T14:37:14.057'' truncate table #objs -- this encapsulation into exec allow update without dependency from fn__script_trace insert #objs(srv_id,db_id,usr,id,[name],[sql],rel,dt,ev,evot,[type]) select a.srv_id,a.db_id,a.usr,a.id,a.[obj],a.[code], case when a.rel is null then convert(sysname,a.dt,12)+''.''+ replace(left(convert(sysname,a.dt,8),5),'':'','''') else convert(sysname,a.rel) end as rel, a.dt, upper(left(ev.cod,charindex(''_'',ev.cod)-1)) event, upper(substring(ev.cod,charindex(''_'',ev.cod)+1,128)) ev_obj_type, o.type -- select top 10 * from fn__script_trace(default,default,default) a -- obj must locally exists to ensure parent correct relations -- (drop of table do not involve trigger, index etc) left join sys.objects o with (nolock) on o.[name]=a.[obj] left join sys.indexes i with (nolock) on i.[name]=a.[obj] left join fn__script_sysobjs((select obj from tids)) so on so.cod=object_name(i.object_id) join fn__script_sysobjs((select ev from tids)) ev on a.ev=ev.id where dt>=@sdt and a.flags in (''ver'') -- obj. and parent must exists (but include script for data) and not (coalesce(o.object_id,i.object_id) is null and a.[obj]!=''DATA_SCRIPT'' ) -- exclude generated objs and not (charindex(''generated by sp__script_alias'',a.[code]) between 20 and 80 or charindex(''g:sp__script_alias'',a.[code]) between 3 and 20 ) -- and a.udt is null and a.usr like @usr and so.id is null -- and index do not refer to system obj order by dt,id -- exclude forwarded objs update o set uinfo=left(cast(oinfo.val2 as nvarchar(4000)),128) from #objs o cross apply fn__script_info(o.[name],''v'',''0'') oinfo end -- date else goto help insert #src(line) select ''** - objects in order of:'' insert #src(line) select ''** tables,indexes,functions,views,procs,synonym,triggers'' insert #src(line) select ''** - dropped objects are not scripted'' insert #src(line) select ''** - all the alteration of tables, idxs, etc.'' insert #src(line) select ''** - only last of many alterations of fn & sp'' insert #src(line) select replicate(''*'',79)+''/'' if @dbg>1 select * from #objs o order by dt desc,id desc -- sp__script_history ''2011-04-15 19:13:02.520'' -- sp__script ''2267'' -- select not dropped objects -- drop table #obj_to_script -- declare @excludes table(obj sysname) select identity(int,1,1) as row,o.*, -- 110622\s.zaglio: round up to 10 minutes substring(dbo.fn__format(o.dt,''YYYYMMDD_HHMM'',default),3,10)+''0''+usr.usr as usdt, uinfo into #obj_to_script -- select * from ( select [name],ev,evot, max(rel) as rel, max(dt) as dt, max(id) id -- case when count(*)>1 then max(id) else null end as id from #objs where ev!=''DROP'' group by [name],ev,evot -- ,case evot when ''table'' then dt else 0 end -- causes duplicates ) o left join ( select [name],ev,evot, max(rel) as rel, max(dt) as dt, max(id) id -- case when count(*)>1 then max(id) else null end as id from #objs where ev=''DROP'' group by [name],ev,evot ) d -- ropped on d.[name]=o.[name] and d.evot=o.evot /*and d.ev!=o.ev*/ and d.dt>=o.dt join #objs usr on o.id=usr.id and (@usr='''' or usr.usr=@usr) left join @excludes ex on o.[name] like ex.[obj] where d.ev is null and ex.[obj] is null and (not uinfo like ''generated by sp__script_%'' or uinfo is null ) order by case o.evot when ''table'' then 10 when ''index'' then 20 when ''function'' then 30 when ''view'' then 40 when ''procedure'' then 50 when ''synonym'' then 60 when ''trigger'' then 70 -- can use some other func/proc/view else 99 end ,dt,id drop table #objs -- show list of filtered objects to allow visual exclusion select name,ev,evot,rel,dt,uinfo from #obj_to_script -- declare @id int,@usr sysname,@dt datetime,@evot sysname -- truncate table #src insert #src(line) select '''' select @tmp='''' declare cs cursor local for select name,ev,id,dt,usdt,evot -- select * from #obj_to_script order by row open cs while 1=1 begin fetch next from cs into @obj,@ev,@id,@dt,@usr,@evot if @@fetch_status!=0 break if @usr!=@tmp begin insert #src(line) select '''' insert #src(line) select ''/*''+dbo.fn__format(@usr,''*< '',75)+'' */'' end select @obj_id=dbo.fn__hex(@id), @lbl=''skip_''+lower(dbo.fn__format(@obj,''AN'',default)) if @drop=1 begin -- try drop existing object if is not an alter table if @evot in (''procedure'',''function'',''synonym'',''view'',''trigger'') exec sp__script @obj,@opt=''drop'' else begin if @evot =''table'' and @ev=''create'' begin insert #src(line) select ''if exists(select null from sys.objects where name=''''''+@obj+'''''') '' insert #src(line) select ''goto ''+@lbl end if @evot =''index'' and @ev=''create'' begin insert #src(line) select ''if exists(select null from sys.indexes where name=''''''+@obj+'''''') '' insert #src(line) select ''goto ''+@lbl end exec sp__script @obj_id,@opt=''drop'' end if @lbl!=''skip_data_script'' -- because all data_script has the same label insert #src select @lbl+'':'' end else begin if @evot in (''procedure'',''function'') insert #src(line) select ''go'' exec sp__script @obj_id insert #src(line) select ''go'' end select @tmp=@usr end -- while of cursor close cs deallocate cs insert #src(line) select '''' insert #src(line) select ''goto ret'' insert #src(line) select '''' insert #src(line) select ''err_drp:'' insert #src(line) select '' raiserror(''''utilities must be installed before this operation'''',11,1)'' insert #src(line) select '' goto ret'' insert #src(line) select ''ret:'' exec sp__print_table ''#src'' drop table #src goto ret -- =================================================================== errors == err_trc: exec @ret=sp__err ''fn__script_trace is required'',@proc goto ret err_log: exec @ret=sp__err ''logddl not initialized'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope generate script for historicized objects. Notes func,proc,synonym, Parameters @what can be: * name of a single object: will list last 1000 modifications * id of trace where to begin: will script it * ISO8601 date of trace where to begin (aaaa-mm-ggThh:mm:ss.mmm) or (aaaa-mm-gg hh:mm:ss.mmm) will script all objects from that date * ISO8601 date\\pc\usr will script from that date of objects modified by "\\pc\usr" * a data script that begin with "IF " or "INSERT " or "exec " @list list objects separated by |,; if @iwhat is a script instruction, the @list excludes objects if @iwhat is a group name, the @list define and re-define membership (sys objects are automatically excluded) @grp (TODO)group name for objects selected between @iwhat and @excludes @opt option description nodrop do not script as code using sp_executesql Fields list mean tid type of object id row table id srv_id server id db_id database id lid local object id flags ver=version or 0(Zero) obj object name or hash des sql command usr_id user id app_id application id rel release captured from header dt utc datetime udt sync datetime Examples sp__script_history "2011-05-06 17:37:31.837" -- script all objs changed in the last 120 days by user X from pc Y sp__script_history "-120\\Y\X" -- insert data script sp__script_history '''' if not exists(select null from tbl where id=123) insert tbl(id,cd,txt) select 123,''''''''cd'''''''',''''''''txt'''''''' '''' '' select @ret=-1 if object_id(''log_ddl'') is null begin exec sp__printframe ''The log_ddl table is absent.'', ''Use sp__script_trace_db to install the tracer'' goto ret end help_trace_view: select @iwhat=upper(@iwhat) if not object_id(''fn__script_trace'') is null begin select @sql='' select top (%top%) convert(binary(4),a.id) as id, convert(binary(4),a.srv_id) as srv_id, convert(binary(4),a.db_id) as db_id, a.obj, a.flags, a.usr, a.code, a.rel, upper(left(ev.cod,charindex(''''_'''',ev.cod)-1)) event, upper(substring(ev.cod,charindex(''''_'''',ev.cod)+1,128)) ev_obj_type, upper(left(ev.cod,charindex(''''_'''',ev.cod)-1)) event, a.dt from fn__script_trace(%what%,default,default) a join fn__script_sysobjs((select ev from tids)) ev on a.ev=ev.id where %cond% order by dt desc,id desc '' if @iwhat is null select @iwhat=''default'',@cond=''1=1'' else if left(@iwhat,2)=''0x'' select @cond=''id=''+@iwhat,@iwhat=''default'' else select @iwhat=dbo.fn__str_quote(@iwhat,''''''''),@cond=''1=1'' exec sp__str_replace @sql out,''%top%|%what%|%cond%'',@top,@iwhat,@cond if @dbg>0 exec sp__printsql @sql exec(@sql) if @@error!=0 and @dbg=0 exec sp__printsql @sql end else exec sp__printf ''\n*** fn__script_trace absent; will be installed from this sp ***'' -- ===================================================================== exit == ret: return @ret end -- proc sp__script_history' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_history: -- =================================================== sp__script_info_tags_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_info_tags_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140117 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_info_tags_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_info_tags_test') with nowait goto skip_sp__script_info_tags_test end if @ver>140117 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_info_tags_test') with nowait goto skip_sp__script_info_tags_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_info_tags_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_info_tags_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_info_tags_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:extract,tags,test v:140117\s.zaglio: added special cases (as notes, see below) v:140114\s.zaglio: adapted to new info_Tags v:130926\s.zaglio: added dbg and test of parse of name v:130925\s.zaglio: test fn for all objects definitions v:130719\s.zaglio: test for fn__Script_info_tags r:130718\s.zaglio: test for fn__Script_info_tags o:130519\s.zaglio:sp__script_info_tags_test_old d:130519\s.zaglio:sp__script_info_tags_test_old t:sp__script_info_tags_test @dbg=1 */ CREATE proc sp__script_info_tags_test @obj sysname = null, @opt sysname = null, @dbg int=0 as begin try set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @sql nvarchar(max),@grps sysname,@row int -- =========================================================== initialization == select @obj=isnull(nullif(@obj,''''),''%'') -- ======================================================== second params chk == -- =============================================================== #tbls init == create table #results( id int, obj sysname, xt sysname, sts varchar(2), err nvarchar(4000) ) -- ===================================================================== body == insert #results(id,obj,xt) select object_id,[name],[type] from sys.objects o where [type] in (''P'',''V'',''TF'',''FN'',''IF'',''FI'',''TR'') and name like @obj union -- special cases for db triggers select object_id,[name],''TD'' from sys.triggers o where parent_id=0 -- means db trigger declare cs cursor local for select r.obj,definition from #results r join sys.sql_modules m on m.object_id=r.id open cs while 1=1 begin fetch next from cs into @obj,@sql if @@fetch_status!=0 break if @dbg>0 exec sp__printf ''-- processing "%s"'',@obj begin try select top 0 * into #t from fn__script_info_tags(@sql,@grps,@row) drop table #t update #results set sts=''ok'' where obj=@obj end try begin catch update #results set sts=''ko'',err=error_message() where obj=@obj end catch end -- cursor cs close cs deallocate cs if @dbg>0 exec sp__printf ''-- test parse of name'' declare cs cursor local for select r.obj,definition from #results r join sys.sql_modules m on m.object_id=r.id open cs while 1=1 begin fetch next from cs into @obj,@sql if @@fetch_status!=0 break if @dbg>0 exec sp__printf ''-- processing "%s"'',@obj begin try declare @parsed sysname select @parsed=parsename(val3,1),@row=row from fn__script_info(@obj,''#'',default) f where f.obj=@obj if @parsed!=@obj or @row<1 update #results set sts=''ko'',err=isnull(err+'';'','''')+''obj name wrong parse'' where obj=@obj else update #results set sts=''ok'' where obj=@obj and left(sts,2)!=''ko'' end try begin catch update #results set sts=''ko'',err=error_message() where obj=@obj end catch end -- cursor cs close cs deallocate cs if @dbg>0 exec sp__printf ''-- test artefact cases'' if 1=(select count(*) from ( select * from fn__script_info_tags('' /* leave this l: g:web v:130515\s.zaglio: /*test1*/ v:130129\s.zaglio: recreate procedure */ create view vi as select 1 as one,2 two,3 three /* last but not least create */ ... /* wrong comment or something inside a string '',''#'',default) rst union ( select ''#'' as tag, 257 as row, ''create'' as val1, ''view'' as val2, ''[vi]'' as val3, null as sts ) ) cnt) insert #results(sts,obj,xt) select ''ok'',''_artefact case'','''' else insert #results(sts,obj,xt) select ''ko'',''_artefact case'','''' goto skip_cases -- ============================================================ special cases == -- 140117\s.zaglio select * from fn__script_info_tags('' /* leave this l: g:web v:131212\author.1: comment v:131204\author.2: comment Non properly conformant comment print @@version print @@servername */ -- v1.0.090721/fname l. -- old style comment -- v1.0.090603/fname l. -- old style comment -- another generic comment CREATE PROCEDURE SP_SCRIPT_INFO_TAGS_TEST1 as print 10 '',default,default) select * from fn__script_info_tags('' /* leave this l:see LICENSE file g:utility v:091216\s.zaglio:added @@servername v:091018\s.zaglio: Statistic of SQL-Server - System parameters for dynamic collection. @@cpu_busy/1000 - Returns the time in seconds that the CPU has spent working since SQL Server was last started. @@io_busy/1000 - Returns the time in seconds that SQL Server has spent performing */ /* Daily Version. Output - Table TBL_SERVERSTATISTICS. A Table include Row per run a Procedure,except Saturday. -- select * from TBL_SERVERSTATISTICS -- select * from TBL_SERVERSTATISTICS_PRIOR */ CREATE PROCEDURE [dbo].[sp__perf_daily] ( @BIT_DELETE_RESULTS BIT = 0 ) AS print 10 '',default,default) skip_cases: -- =========================================================== output results == exec sp__select_astext '' select sts,obj,xt,err from #results order by sts '' exec sp__printf '''' exec sp__prints ''8<'' exec sp__printf '''' if exists(select top 1 null from #results where sts=''ko'') raiserror(''test failed'',16,1) -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test fn__script_info_tags for all objects definitions Parameters [param] [desc] @obj filter for object(s) (default is %) @opt (not used) @dbg 1 print object in process '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_info_tags_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_info_tags_test: -- ============================================================= sp__script_jobs select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_jobs',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140109 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_jobs') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_jobs') with nowait goto skip_sp__script_jobs end if @ver>140109 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_jobs') with nowait goto skip_sp__script_jobs end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_jobs') with nowait if exists( select top 1 null from sys.objects where name='sp__script_jobs' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_jobs] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140109\s.zaglio: problem of ending \ when scripted to file. v:090909\s.zaglio: from ms support -- single test exec sp__script_jobs exec sp__run_cmd ''type %temp%\%@@servername%_jobs.sql'' exec sp__run_cmd ''del %temp%\%@@servername%_jobs.sql /q'' -- out to temp table create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script_jobs @out=''#src'' select * from #src drop table #src -- out to specific dir declare @out sysname exec sp__get_env @out out,''allusersprofile'' exec sp__script_jobs @out=@out,@dbg=1 exec sp__run_cmd ''dir "%allusersprofile%"'' exec sp__run_cmd ''del "%allusersprofile%\%@@servername%_jobs.sql" /q'' -- exec sp__run_cmd ''del c:\temp\*.* /q /s /f'' */ CREATE proc [dbo].[sp__script_jobs] @server nvarchar(30)=null, -- server name to run script on. by default, local server. @out sysname=null, -- can be #src or must terminate with .sql or \. @dbg bit=0 as begin set nocount on if @server is null select @server=@@servername --sp_oa params declare @cmd nvarchar(255) -- command to run declare @osqlserver int -- oa return object declare @hr int -- return code --user params declare @filename nvarchar(200) -- file name to script jobs out --sql dmo constants declare @scripttype nvarchar(50) declare @script2type nvarchar(50) set @scripttype = ''327'' -- send output to file, transact-sql, script permissions, test for existence, used quoted characters. set @script2type = ''3074'' -- script jobs, alerts, and use codepage 1252. --set the following properties for your server declare @tmp sysname exec sp__get_temp_dir @tmp out set @server = lower(@server) if right(@out,1)=''\'' select @out=left(@out,len(@out)-1) if not @out is null and right(@out,4)!=''.sql'' and @out!=''#src'' select @filename=@out else set @filename = @tmp select @filename=@filename+''\''+@server+''_jobs.sql'' if @dbg=1 exec sp__printf ''out to:%s'',@filename --create the sqldmo object exec @hr = sp_oacreate ''sqldmo.sqlserver'', @osqlserver out --set windows authentication exec @hr = sp_oasetproperty @osqlserver, ''loginsecure'', true --connect to the server exec @hr = sp_oamethod @osqlserver,''connect'',null,@server --script the job out to a ntext file set @cmd = ''jobserver.jobs.script('' + @scripttype + '',"'' + @filename +''",'' + @script2type + '')'' create table #devnul (t ntext) insert into #devnul -- prevent output exec @hr = sp_oamethod @osqlserver, @cmd drop table #devnul if @out=''#src'' begin exec sp__file_read @filename,''#src'',@step=10 select @cmd=''del "''+@filename+''" /q'' exec sp__run_cmd @cmd,@nooutput=1 end --close the connection to sql server --if object is not disconnected, the processes will be orphaned. exec @hr = sp_oamethod @osqlserver, ''disconnect'' --destroy object created. exec sp_oadestroy @osqlserver end -- [sp__script_jobs]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_jobs: -- ============================================================= sp__script_move select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_move',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130802.1800 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_move') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_move') with nowait goto skip_sp__script_move end if @ver>130802.1800 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_move') with nowait goto skip_sp__script_move end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_move') with nowait if exists( select top 1 null from sys.objects where name='sp__script_move' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_move] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:move,back,history,historicize v:130802.1800\s.zaglio: adapted to new sp__script_template v:121122\s.zaglio: log n moved instead of @top v:121107\s.zaglio: added nolock near count(*) v:121003\s.zaglio: used sp__flds_list to follow synonyms v:121002\s.zaglio: follow the synonyms of tables using sp__script_pkey v:120921\s.zaglio: better skip when single table v:120920\s.zaglio: abount log times of @top instead of @n v:120919\s.zaglio: due runtime errors, some correction to aliases v:120918\s.zaglio: done a compilable version without errors r:120917\s.zaglio: adopting sp_select_asform r:120913\s.zaglio: modifing template and correct sp__script_template r:120912\s.zaglio: modifing template d:120910\s.zaglio: sp__script_copy r:120910\s.zaglio: removed tag opt. and converting in multi tab. r:120903\s.zaglio: changing to multi table v:120828\s.zaglio: added tag option v:120827\s.zaglio: added log of times v:120820\s.zaglio: added @ms... vars v:120810\s.zaglio: done r:120809\s.zaglio: script copy or move data t:sp__script_move_test @dbg=1 */ CREATE proc sp__script_move @tbls nvarchar(4000) = null, -- sa|sb|sc @dsts nvarchar(4000) = null, -- da|db|dc @joins nvarchar(max) = null, -- sa.id=sb.rid|sb.id=sc.rid @where nvarchar(4000) = null, -- dt>... @order sysname = null, @top sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @e_msg sysname, @e_p1 sysname select @dbg=0, @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == select -- @tbl= dbo.fn__sql_normalize(@tbl,default), -- @dst= dbo.fn__sql_normalize(@dst,default), @where= dbo.fn__sql_normalize(@where,default), @order= dbo.fn__sql_normalize(@order,''ord''), @top= dbo.fn__sql_normalize(@top,''top''), @joins= case when ltrim(rtrim(@joins))=''|'' then '''' else isnull(@joins,'''') end if left(@top,1)=''#'' goto err_top if dbo.fn__str_count(@tbls,''|'')!=dbo.fn__str_count(@tbls,''|'') goto err_dp1 if @joins!='''' and dbo.fn__str_count(@tbls,''|'')!=dbo.fn__str_count(@joins,''|'') goto err_dp2 -- ============================================================== declaration == declare @i int,@j int, @tbl sysname,@dst sysname, @dst_db sysname, @dst_tbl sysname, @pkey nvarchar(4000), -- list of pk fields @on_pkeys nvarchar(4000), -- list of tbl.pkf1=tmp.pkf1 and ... @excludes sysname, @notrg bit, @copy bit, @back bit, -- options @idx bit, -- options @flds nvarchar(4000), -- fields @tbl_flds nvarchar(4000), -- fields with tbl. prefix @lbl sysname, -- local label for goto @keys sysname, -- #tmp table name for keys of @tbl @src bit, -- 1=return results into #src, 0=print @ntop sysname, -- value of @top @log sysname, -- name of log table @join_on nvarchar(1024), -- on condition @alias sysname,@join sysname, @tmp sysname, @mix sysname, -- inner sp @id int, @end_declare bit create table #tpl( lno int identity primary key, line nvarchar(4000) ,procid int default(@@procid) ) create table #tpl_sec( lno int identity, section sysname, line nvarchar(4000) ,procid int default(@@procid) ) create table #tpl_cpl(tpl binary(20),section sysname,y1 int,y2 int) if exists(select top 1 null from #tpl) goto err_tpl create table #vars (id nvarchar(16),value sql_variant) if object_id(''tempdb..#src'') is null begin create table #src(lno int identity primary key,line nvarchar(4000)) select @src=0 end else select @src=1 create table #joins( id int identity, src sysname, alias sysname, dst sysname, [join] nvarchar(4000) null, join_on nvarchar(4000), [pkey] nvarchar(1024) null, keys nvarchar(1024) null, [on_pkeys] sysname null, [main] sysname null, [main_alias] sysname null, dst_flds nvarchar(4000) null, tbl_flds nvarchar(4000) null, lbl sysname null -- normalized rtbl for skip_ ) -- =========================================================== initialization == select @mix=''#mix'', @back =charindex(''|back|'',@opt), @notrg=charindex(''|notrg|'',@opt), @copy =charindex(''|copy|'',@opt), @idx =charindex(''|idx|'',@opt), @log =isnull(dbo.fn__str_between(@opt,''log:'',''|'',default), ''tmp_script_copy_log'' ), @excludes='''', @excludes=@excludes+case @copy when 1 then ''|move'' else '''' end, @excludes=@excludes+case @notrg when 1 then ''|trgs'' else '''' end, @excludes=@excludes+case @dbg when 0 then ''|dbg'' else '''' end, @excludes=@excludes+case @idx when 0 then ''|idxs'' else '''' end, @ntop=dbo.fn__Str_between(@top,''('','')'',default), @top=replace(@top,@ntop,''@top'') -- load local template exec sp__Script_templates ''move'' -- insert before here -- @end_declare=1 -- ======================================================== second params chk == insert into #joins(alias,src,dst,join_on) select alias=case charindex('':'',src.token) when 0 then src.token else left(src.token,charindex('':'',src.token)-1) end, src=case charindex('':'',src.token) when 0 then src.token else substring(src.token,charindex('':'',src.token)+1,128) end, dst.token, isnull(replace(replace(jj.token,''|'','' and ''),''"'',''''''''),'''') from dbo.fn__str_split(@tbls,''|'') src left join dbo.fn__str_split(@dsts,''|'') dst on src.pos=dst.pos left join dbo.fn__str_split(@joins,''|'') jj on jj.pos=dst.pos update #joins set lbl=dbo.fn__format(alias,''AN'',default) -- extract table from join_on declare cs cursor local for select id,src,alias,join_on from #joins order by id open cs while 1=1 begin fetch next from cs into @id,@tbl,@alias,@join_on if @@fetch_status!=0 break -- 121002\s.zaglio: will follow synonyms exec sp__script_pkey @pkey out,@tbl,@sep='','',@opt=''flds'' if @pkey is null goto err_pk exec sp__flds_list @flds out,@tbl,'','' -- exec sp__printf ''tbl:%s pkey:%s flds:%s'',@tbl,@pkey,@flds select @keys=''#keys_''+lower(dbo.fn__format(@tbl,''ANs'',default)), @pkey=dbo.fn__flds_quotename(@pkey,'',''), @on_pkeys=replace(dbo.fn__str_exp(@alias+''.%%=tmp.%%'',@pkey,'',''), '','','' and '' ), @tbl_flds=dbo.fn__str_exp(@alias+''.%%'',@flds,'',''), @join='','' -- extra tables/aliases from joins if @joins='''' select @join=@tbl,@join_on=@keys else begin select @i=charindex(''.'',@join_on) while @i>0 begin select @j=@i-1 while @j>0 and not substring(@join_on,@j,1) like ''[[ =,]'' select @j=@j-1 select @alias=substring(@join_on,@j+1,@i-@j-1) select @tmp=src from #joins where @alias in (alias,src) if charindex('',''+@tmp+'','',@join)=0 and @tmp!=@tbl select @join=@join+@tmp+'','' select @i=charindex(''.'',@join_on,@i+1) end if @join = '','' select @join=@tbl else select @join=substring(@join,2,len(@join)-2) end update #joins set [join]=@join, join_on=@join_on, pkey=@pkey, [keys]=@keys, on_pkeys=@on_pkeys, -- template tokens do not support crlf -- dst_flds=dbo.fn__str_flow(@flds,'','',default), -- tbl_flds=dbo.fn__str_flow(@tbl_flds,'','',default), dst_flds=@flds, tbl_flds=@tbl_flds, main=src, main_alias=alias where id=@id end -- cursor cs close cs deallocate cs -- select @proc sp,* from #joins if exists( select null from #joins where object_id(src) is null or object_id(dst) is null ) goto err_tbl if @joins!='''' and exists( select null from #joins where isnull(join_on,'''')='''' and id!=1 ) goto err_jn if @tbls is null or @dsts is null or @where is null -- and @opt=''||'' goto help -- if joins are specified the 1st table is the main table if @joins!='''' begin update #joins set [join]=keys,[join_on]=on_pkeys where id=1 update j set j.keys=jj.keys, j.on_pkeys=jj.on_pkeys, j.main=jj.src, j.main_alias=jj.alias from #joins j join #joins jj on j.[join]=jj.src -- where j.id!=1 end -- select @proc sp,* from #joins -- ===================================================================== body == -- common info insert #vars select ''%top%'',@top insert #vars select ''%ntop%'',@ntop insert #vars select ''%where%'',@where insert #vars select ''%orderby%'',@order insert #vars select ''%log%'',@log exec sp__select_asform ''#joins'',''id=1'',@opt=''#vars'' if not object_id(''tempdb..''+@mix) is null drop proc #mix exec(''create proc ''+@mix+'' @section sysname,@excludes sysname=null,@dbg int=0 as select @excludes=''''''+@excludes+''''''+isnull(''''|''''+@excludes,'''''''') exec sp__script_template @section, @opt=''''replace"'''', @excludes=@excludes ,@dbg=@dbg '') -- manually expand %log_times% for problem with backward compatibility exec sp__script_template ''%log_times_section%'',''%log_times%'' exec sp__script_template ''%log_commit_section%'',''%log_commit%'' exec @mix ''%header%'',@dbg=@dbg if @joins!='''' exec @mix ''%begin%'',@dbg=@dbg -- select @proc sp,* from #joins declare cs cursor local for select id,src,dst,alias,join_on,[join],pkey,keys,on_pkeys from #joins -- from last because main table is used in join with details order by id desc open cs while 1=1 begin fetch next from cs into @id,@tbl,@dst,@alias,@join_on,@join, @pkey,@keys,@on_pkeys if @@fetch_status!=0 break select @where=''id=''+cast(@id as sysname) exec sp__select_asform ''#joins'',@where,@opt=''#vars'' if @joins='''' exec @mix ''%body_single_table%'',@dbg=@dbg else begin select @excludes=case @id when 1 then ''main'' else null end exec @mix ''%body_group%'',@excludes,@dbg=@dbg end end -- cursor cs close cs deallocate cs if @joins!='''' exec @mix ''%end%'',@dbg=@dbg exec @mix ''%footer%'',@dbg=@dbg -- if @back=1 exec @mix ''%back%'' exec @mix ''%catch%'',@dbg=@dbg drop proc #mix if @src=0 exec sp__print_table ''#src'' goto ret -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1 goto ret err_top: select @e_msg=@top goto err err_pk: select @e_msg=''table %s without primary key'',@e_p1=@tbl goto err err_tbl: select @e_msg=''source table not found'' goto err err_jn: select @e_msg=''some join are not specified'' goto err err_tpl: select @e_msg=''a tpl already exists from parent proc'' goto err err_dp1: select @e_msg=''@dsts count is different from @tbls'' goto err err_dp2: select @e_msg=''@joins count is differente from @tbls'' goto err goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create a script to copy rows from tables to their copy; can move related data if @where contain joins conditions. can be used to historicize data Parameters (*) duty parameters #src if present, store result here @tbls (*)source tables names separated by "|"; aliases must prefixed with ":" (ex: "A1:ARCHIVE1") @dsts (*)destination table (must in the same order of sources) @joins when more than one table is involved, can/must be joined using these expressions, separated by "|" @where (*)condition that split tables into data to move and data to keep back from history @order optional order by condition @top optional top rows (n) or percent (n%) @opt options run run the script immediatelly sel return results as select copy copy only, do not delete original rows notrg do not disable triggers back reverses @where and move back data from destination to original table idx include disable and then rebuild of indexes nfo print count of moved rows and store times into log table: create table %log%( dt datetime, tbl sysname, n int, ms_key int, ms_alt int, ms_ins int, ms_del int, ms_commit int ) log:tbl store log info into table tbl instead of default tmp_script_copy_log Notes A check of number of lines moved, to prevent move of all data, will be done. See sp__script_align Examples -- move single table sp__script_move @tbls = "tbl", @dsts = "history..tbl", @where = "not dt #k move T1 from T1+#k move T2 from T1+#k+T2 move T3 from T1+#k+T2+T3 -- note this */ sp__script_move @tbls = "T1:tbl1|T2:tbl2|T3:tbl3", @dsts = "H1|H2|H3", -- this are synonyms @joins= "T1.id=T2.rid|T1.id=T3.rid", @where = "not dt #k move T1 from T1+#k move T2 from T1+#k+T2 move T3 from T1+#k+T3 -- note this */ '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__script_copy' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_move: -- ======================================================== sp__script_move_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_move_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130802 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_move_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_move_test') with nowait goto skip_sp__script_move_test end if @ver>130802 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_move_test') with nowait goto skip_sp__script_move_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_move_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_move_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_move_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130802\s.zaglio: test for sp__Script_move */ CREATE proc sp__script_move_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == if not object_id(''test_move'') is null drop table test_move if not object_id(''test_move_copy'') is null drop table test_move_copy create table test_move(id int identity primary key,a int,b sysname) insert test_move select 1,''one'' insert test_move select 2,''two'' select * into test_move_copy from test_move exec sp__script_move ''t:test_move'',''test_move_copy'', @where=''1=1'', @opt=''back|move|nfo'', @dbg=@dbg -- ================================================================== dispose == dispose: drop table test_move drop table test_move_copy goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test for sp__Script_move Parameters [param] [desc] @opt options @dbg '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_move_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_move_test: -- ============================================================== sp__script_ole select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_ole',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100328 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_ole') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_ole') with nowait goto skip_sp__script_ole end if @ver>100328 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_ole') with nowait goto skip_sp__script_ole end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_ole') with nowait if exists( select top 1 null from sys.objects where name='sp__script_ole' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_ole] begin try exec dbo.sp_executesql @statement = N'/* Leave this unchanged doe MS compatibility l:see LICENSE file g:utility,script v:100328\s.zaglio: renamed to sp__script_ole v:090801.1900\S.Zaglio: vertion 2.5 of sp__script (rewrite of old sp__generate_script) todo: test on checks, indexes, tables with foreign keys t:sp__script ''dtproperties'',@print=0 t: -- sp__script -- give us the help with #src structure create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script_ole ''sp__script_ole'',''#src'' exec sp__script_ole ''#src'' -- this print the source drop table #src h: SQLDMO on MSDN see http://msdn.microsoft.com/en-us/library/aa258911(SQL.80).aspx h: for specific help see http://msdn.microsoft.com/en-us/magazine/bb985852.aspx h: for generic help see http://msdn.microsoft.com/en-us/magazine/cc301940.aspx */ CREATE proc [dbo].[sp__script_ole] @obj sysname=null out, -- object name and output table name @out nvarchar(512)=null out, -- file name or table or variale @conn sysname=null, -- svr or svr|db or svr|db|uid or svr|db|uid|pwd @oc int=null, @step smallint=10, @print bit=1, @dbg bit=0 as begin set nocount on /* Compatibility notes with MSSQL2005, MSSQL2008 To allow this sp to work with 2005 & 2008, must install backward feature on SQL2K and update on SQL2K5 download: http://download.microsoft.com/download/f/7/4/f74cbdb1-87e2-4794-9186-e3ad6bd54b41/SQLServer2005_BC.msi (can need reboot) Probably need also to disable some surface protection from SQL2005 surface area configuration such as: - query remote ad hoc (enable openrowset, opendatase) - ole automation - enable xp_cmdshell Can be done by code EXECUTE sp_configure ''show advanced options'', 1 RECONFIGURE WITH OVERRIDE EXECUTE sp_configure EXECUTE sp_configure ''xp_cmdshell'', ''1'' RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''Ole Automation Procedures'', ''1'' RECONFIGURE WITH OVERRIDE EXECUTE sp_configure ''SMO and DMO XPs'', ''1'' RECONFIGURE WITH OVERRIDE -- MSSQL2008 -- EXECUTE sp_configure ''Ad Hoc Distributed Queries'',1 RECONFIGURE WITH OVERRIDE EXECUTE sp_configure EXECUTE sp_configure ''show advanced options'', 0 RECONFIGURE WITH OVERRIDE */ declare @r int set @r=0 declare @msg nvarchar(4000) declare @src_name sysname select @src_name=''#src'' declare @dir nvarchar(256) declare @file nvarchar(256) declare @cmd sysname declare @crlf nvarchar(2) set @crlf=char(13)+char(10) declare @sql nvarchar(4000) declare @n int,@i int, @k int, @drop_file bit declare @line nvarchar(4000) declare @out_var bit,@out_file bit,@out_tbl bit declare @svr sysname,@db sysname,@uid sysname,@pwd sysname,@trusted bit declare @own sysname declare @ntype int select @db=parsename(@obj,3) select @own=parsename(@obj,2) select @obj=parsename(@obj,1) if @own is null set @own=''dbo'' select @own=dbo.fn__sql_unquotename(@own) select @obj=dbo.fn__sql_unquotename(@obj) /* select @obj=@own+''.''+@obj --> give: cmd:addobjectbyname|source:ODSOLE Extended Procedure|desc: Incompatibilità tra tipi.|svr:16711422|@transf: */ if @obj=@src_name goto print_src if @out=@src_name select @print=null -- return db_name() and server if nulls if @conn is null and @db is null select @db=db_name() exec sp__parse_conn @conn,@svr out,@db out,@uid out,@pwd out,@trusted out /* if not @obj is null and charindex(''.'',@obj)>0 begin set @own=dbo.fn__str_at(@obj,''.'',1) set @obj=dbo.fn__str_at(@obj,''.'',2) end */ -- sqldmo_script_type vars -- see: http://msdn.microsoft.com/en-us/library/aa225364(SQL.80).aspx declare @sqldmoscript_default int , @sqldmoscript_drops int , @sqldmoscript_objectpermissions int declare @sqldmoscript_primaryobject int , @sqldmoscript_clusteredindexes int , @sqldmoscript_triggers int declare @sqldmoscript_databasepermissions int , @sqldmoscript_permissions int , @sqldmoscript_tofileonly int declare @sqldmoscript_bindings int , @sqldmoscript_appendtofile int , @sqldmoscript_nodri int declare @sqldmoscript_uddtstobasetype int , @sqldmoscript_includeifnotexists int , @sqldmoscript_nonclusteredindexes int declare @sqldmoscript_indexes int , @sqldmoscript_aliases int , @sqldmoscript_nocommandterm int declare @sqldmoscript_driindexes int , @sqldmoscript_includeheaders int , @sqldmoscript_ownerqualify int declare @sqldmoscript_timestamptobinary int , @sqldmoscript_sorteddata int , @sqldmoscript_sorteddatareorg int declare @sqldmoscript_transferdefault int , @sqldmoscript_dri_nonclustered int , @sqldmoscript_dri_clustered int declare @sqldmoscript_dri_checks int , @sqldmoscript_dri_defaults int , @sqldmoscript_dri_uniquekeys int declare @sqldmoscript_dri_foreignkeys int , @sqldmoscript_dri_primarykey int , @sqldmoscript_dri_allkeys int declare @sqldmoscript_dri_allconstraints int , @sqldmoscript_dri_all int , @sqldmoscript_driwithnocheck int declare @sqldmoscript_noidentity int , @sqldmoscript_usequotedidentifiers int -- format output definitions declare @sqldmoscript_4usequoted int -- only columns and without collate -- sqldmo_script2_type vars -- see: http://msdn.microsoft.com/en-us/library/aa225398(SQL.80).aspx declare @sqldmoscript2_default int , @sqldmoscript2_ansipadding int , @sqldmoscript2_ansifile int declare @sqldmoscript2_unicodefile int , @sqldmoscript2_nonstop int , @sqldmoscript2_nofg int declare @sqldmoscript2_marktriggers int , @sqldmoscript2_onlyusertriggers int , @sqldmoscript2_encryptpwd int declare @sqldmoscript2_separatexps int , @sqldmoscript2_extendedproperty int , @sqldmoscript2_extendedonly int declare @sqldmoscript2_nocollation int /* test: declare @tbl sysname, @new sysname select @tbl=''put here the table'',@new=@tbl+''_renamed'' create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script_ole @tbl,''#src'',@oc=1 exec sp__script_ole @tbl,''#src'',@oc=20 exec sp__script_ole @tbl,''#src'',@oc=32 update #src set line=replace(line,@tbl,@new) select coalesce(line,'''') as line from #src order by lno drop table #src */ -- sp__script options declare @oc_tbl smallint,@oc_dri smallint,@oc_trg smallint,@oc_prp smallint, @oc_col smallint, @oc_fk smallint, @oc_end_declare bit select @oc_tbl=1, @oc_dri=20, @oc_trg=32, @oc=coalesce(@oc,@oc_tbl), @oc_prp=128, @oc_col=512, @oc_fk=1024 -- sqldmo_script_type values -- see: http://msdn.microsoft.com/en-us/library/aa225364(SQL.80).aspx set @sqldmoscript_default = 4 set @sqldmoscript_drops = 1 set @sqldmoscript_objectpermissions = 2 set @sqldmoscript_primaryobject = 4 set @sqldmoscript_clusteredindexes = 8 set @sqldmoscript_triggers = 16 set @sqldmoscript_databasepermissions = 32 set @sqldmoscript_permissions = 34 set @sqldmoscript_tofileonly = 64 set @sqldmoscript_bindings = 128 set @sqldmoscript_appendtofile = 256 set @sqldmoscript_nodri = 512 set @sqldmoscript_uddtstobasetype = 1024 set @sqldmoscript_includeifnotexists = 4096 set @sqldmoscript_nonclusteredindexes = 8192 set @sqldmoscript_indexes = 73736 set @sqldmoscript_aliases = 16384 set @sqldmoscript_nocommandterm = 32768 set @sqldmoscript_driindexes = 65536 set @sqldmoscript_includeheaders = 131072 set @sqldmoscript_ownerqualify = 262144 set @sqldmoscript_timestamptobinary = 524288 set @sqldmoscript_sorteddata = 1048576 set @sqldmoscript_sorteddatareorg = 2097152 set @sqldmoscript_transferdefault = 422143 set @sqldmoscript_dri_nonclustered = 4194304 set @sqldmoscript_dri_clustered = 8388608 set @sqldmoscript_dri_checks = 16777216 set @sqldmoscript_dri_defaults = 33554432 set @sqldmoscript_dri_uniquekeys = 67108864 set @sqldmoscript_dri_foreignkeys = 134217728 set @sqldmoscript_dri_primarykey = 268435456 set @sqldmoscript_dri_allkeys = 469762048 set @sqldmoscript_dri_allconstraints = 520093696 set @sqldmoscript_dri_all = 532676608 set @sqldmoscript_driwithnocheck = 536870912 set @sqldmoscript_noidentity = 1073741824 set @sqldmoscript_usequotedidentifiers = -1 -- format set @sqldmoscript_4usequoted =-1 -- sqldmo_script2_type values -- see: http://msdn.microsoft.com/en-us/library/aa225398(SQL.80).aspx set @sqldmoscript2_default = 0 set @sqldmoscript2_ansipadding = 1 set @sqldmoscript2_ansifile = 2 set @sqldmoscript2_unicodefile = 4 set @sqldmoscript2_nonstop = 8 set @sqldmoscript2_nofg = 16 set @sqldmoscript2_marktriggers = 32 set @sqldmoscript2_onlyusertriggers = 64 set @sqldmoscript2_encryptpwd = 128 set @sqldmoscript2_separatexps = 256 set @sqldmoscript2_extendedproperty = 4194304 set @sqldmoscript2_extendedonly=67108864 set @sqldmoscript2_nocollation = 8388608 -- convertion from sp__Script options to sqldmo options declare @type nchar(2),@options2 int ,@options int select @options=case when @oc=@oc_prp then @sqldmoscript_default -- if only xprops when @oc&64=64 then @sqldmoscript_default | @sqldmoscript_ownerqualify | @sqldmoscript_dri_defaults when @oc&@oc_tbl=@oc_tbl then @sqldmoscript_default | @sqldmoscript_dri_defaults | @sqldmoscript_ownerqualify when @oc&@oc_fk=@oc_fk then @sqldmoscript_dri_foreignkeys | @sqldmoscript_nodri | @sqldmoscript_driwithnocheck -- sp__script ''%tbl%'',@oc=134 when @oc&@oc_dri=@oc_dri then @sqldmoscript_nodri | @sqldmoscript_dri_primarykey | @sqldmoscript_nonclusteredindexes | @sqldmoscript_dri_clustered | @sqldmoscript_indexes -- | @sqldmoscript_dri_defaults -- this don''t work when @oc&@oc_trg=@oc_trg then @sqldmoscript_triggers | @sqldmoscript_nodri | 0 else @sqldmoscript_default --| @sqldmoscript_nodri | @sqldmoscript_dri_defaults | @sqldmoscript_ownerqualify | @sqldmoscript_noidentity end if (@options is null) select @options=@sqldmoscript_default set @options2= @sqldmoscript2_ansifile|@sqldmoscript2_unicodefile| case when @oc&@oc_prp=@oc_prp and @oc!=@oc_prp then @sqldmoscript2_extendedproperty when @oc=@oc_prp then @sqldmoscript2_extendedonly else 0 end| case when @oc&@oc_col=@oc_col then 0 else @sqldmoscript2_nocollation end -- HELP if (@obj=''-?'' or @obj is null) goto help if left(@out,1)=''#'' and @out!=@src_name goto err_tmptbl select @sql=quotename(@own)+''.''+quotename(@obj) if @conn is null and dbo.fn__exists(@sql,null)=0 goto err_objnf -- use as @tmp select @msg=''tmp_''+replace(convert(nvarchar(64),newid()),''-'',''_'')+''.sql'' -- a temp destination file is required by OLE method call if @out=@src_name --- we presume that exist and is compatible to (lno,line,...) begin exec sp__get_temp_dir @file out set @file=@file+@msg end else begin create table #src (lno int identity(10,10),line nvarchar(4000)) if @out is null select @out=@msg,@drop_file=1 if charindex(''\'',@out)=0 -- out can be: file [1], dir\ [2] , dir\file [3] begin exec sp__get_temp_dir @file out -- [1] select @file=@file+''\''+@out end else begin if right(@out,1)=''\'' select @file=@out+@msg -- [2] end end -- !=#src select @msg=null select @sql=N''select @type=xtype from [''+@db+'']..sysobjects where [name]=''''''+@obj+'''''''' exec sp_executesql @sql,N''@type nchar(2) out'', @type=@type out /* if @type in (''V'',''P'',''TF'',''FN'',''IF'') begin todo: to refine better select @i=min(colid),@n=max(colid) from syscomments where id=object_id(@obj) while (@i<=@n) begin select @line=[ntext] from syscomments where id=object_id(@obj) and colid=@i select @i=@i+1 insert into #src(line) select token from dbo.fn__str_table(@line,@crlf) order by pos end end -- source in syscomments else begin */ declare @object_types nvarchar(50) -- used to translate sysobjects.type into the bitmap that transfer requires set @object_types=''t v u p d r tr fn tf if '' set @type=case @type when ''tf'' then ''fn'' when ''if'' then ''fn'' else @type end set @ntype=power(2,(charindex(@type+'' '',@object_types)/3)) declare @hr int declare @server int, @transf int -- handle objects select @cmd=''SQLDMO.SQLServer'' exec @hr=sp_oacreate @cmd, @server out if @hr<>0 goto err_dmo select @cmd=''SQLDMO.Transfer'' exec @hr=sp_OaCreate @cmd, @transf out if @hr<>0 goto err_dmo if @trusted=1 begin if @dbg=1 print ''secure login'' select @cmd=''loginsecure'' exec @hr = sp_oasetproperty @server, @cmd, 1 if (@hr <> 0) goto err_dmo select @cmd=''connect'' exec @hr = sp_oamethod @server, @cmd, null, @svr if (@hr <> 0) goto err_dmo end else begin if @dbg=1 print ''connection'' select @cmd=''connect'' if coalesce(@pwd,'''')='''' exec @hr = sp_oamethod @server, @cmd, null, @svr, @uid if (@hr <> 0) goto err_dmo else exec @hr = sp_oamethod @server, @cmd, null, @svr, @uid, @pwd if (@hr <> 0) goto err_dmo end select @cmd=''copydata'' exec @hr = sp_oasetproperty @transf, @cmd, 0 if (@hr <> 0) goto err_dmo select @cmd=''copyschema'' exec @hr = sp_oasetproperty @transf, @cmd, 1 if (@hr <> 0) goto err_dmo --if @type=''ut'' --exec @hr = sp_oasetproperty @transf, ''includedependencies'', 1 if (@hr <> 0) goto err_dmo select @cmd=''addobjectbyname'' exec @hr = sp_oamethod @transf, @cmd, null, @obj, @ntype, @own if (@hr <> 0) goto err_dmo select @cmd=''scripttype'' exec @hr = sp_oasetproperty @transf, @cmd, @options if (@hr <> 0) goto err_dmo if @dbg=1 exec sp__printf ''options=%d'',@options select @cmd=''script2type'' exec @hr = sp_oasetproperty @transf, @cmd, @options2 if (@hr <> 0) goto err_dmo if @dbg=1 exec sp__printf ''options2=%d'',@options2 set @cmd = ''Databases("'' + @db + ''").ScriptTransfer'' if @dbg=1 exec sp__printf ''-- %s'',@cmd create table #devnul (t ntext) insert into #devnul -- prevent output exec @hr=sp_oamethod @server, @cmd,null, @transf, 2, @file if (@hr <> 0) goto err_dmo drop table #devnul /* -- sometimes cause an unk err and not accept the databases cmd declare @object int select @cmd=''databases'' exec @hr = sp_oagetproperty @server, @cmd, @object out if (@hr <> 0) goto err_dmo select @cmd=''item'' exec @hr = sp_oamethod @object, @cmd, @object out, @db if (@hr <> 0) goto err_dmo select @cmd=''scripttransfer'' create table #devnul (t ntext) insert into #devnul exec @hr = sp_oamethod @object, @cmd,null, @transf, 2, @file if (@hr <> 0) goto err_dmo drop table #devnul */ exec sp_oadestroy @transf set @transf=null select @cmd=''disconnect'' exec @hr=sp_oamethod @server, @cmd if (@hr <> 0) goto err_dmo exec sp_oadestroy @server set @server=null exec sp__file_read @file,@src_name,@step=@step,@dbg=@dbg -- correct a problem that the editor introduce with a double #13 or #10 select @sql=''update ''+@src_name+'' set line=replace(replace(line,char(13),'''' ''''),char(10),'''' '''')'' exec(@sql) set @obj=@src_name --end -- use of sqldmo print_src: exec sp__count @src_name,@n=@n out if @n=0 exec sp__printf ''-- no source rows found'' if @dbg=1 exec sp__printf ''%d rows in source'',@n if @n>0 and @print=1 begin if @dbg=1 exec sp__printf ''printing...'' exec sp__print_table ''#src'' end -- print if @print=0 begin if @dbg=1 set @sql=''select * from ''+@obj+'' order by lno'' else set @sql=''select line from ''+@obj+'' order by lno'' exec (@sql) drop table #src end -- c: see http://www.simple-talk.com/sql/t-sql-programming/the-tsql-of-text-files/ if @drop_file=1 begin set @sql=''del /q "''+@file+''"'' if @dbg=1 print @sql exec xp_cmdshell @sql,no_output end goto ret help: select @msg =''\ntmp decl: create table #src (lno int identity(''+convert(sysname,@step)+'',''+convert(sysname,@step)+''),line nvarchar(4000))\n\n'' +''@options can be (NB: cannot be combined):\n'' +''\t@oc_tbl=1 -- table with owner and not chk\n'' +''\t@oc_dri=20 -- pkey,idx and chk\n'' +''\t@oc_trg=32 -- triggers only\n'' +''\t@oc_prp=128 -- with extended properties or only extended prop. if alone\n'' +''\t@oc_col=512 -- add collation definition\n'' +''\t@oc_fk=1024 -- only foreign key(on obj table)\n'' +''\tdefault=@oc_tbl\n'' +''\tfor foreign keys source use "sp__script_fkeys @table"\n'' +''\n'' +''Examples\n'' +''\tsp__script_ole ''''sp__script'''' -- print source\n'' +''\tsp__script_ole ''''sp__script'''',@print=0 -- output a select\n'' +''\tsp__script_ole ''''sp__script'''',@out=''''#src'''',@print=null -- append to standard temp #src table\n'' +''\tsp__script_ole ''''sp__script'''',@out=''''sp__script.sql'''',@print=null -- output to %temp%\sp__script.sql\n'' +''\n'' exec sp__usage ''sp__script_ole'',@extra=@msg select @msg=null goto ret err_tmptbl:select @msg=''-- temp table name must be #src'',@r=1 goto ret err_objnf:select @msg=''-- object "''+@obj+''" not found'',@r=1 goto ret err_dmo: ret: if not (@server is null and @transf is null) begin DECLARE @source nvarchar(255) DECLARE @description nvarchar(255) EXEC @hr = sp_OAGetErrorInfo @transf, @source OUT, @description OUT exec sp__printf ''-- cmd:%s|source:%s|desc:%s|svr:%s|@transf:%d'',@cmd,@source,@description,@server,@transf destory: if not @server is null exec sp_oadestroy @server if not @transf is null exec sp_oadestroy @transf end if not @msg is null exec sp__printf @msg return @r end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_ole: -- ============================================================ sp__script_parse select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_parse',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091128 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_parse') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_parse') with nowait goto skip_sp__script_parse end if @ver>091128 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_parse') with nowait goto skip_sp__script_parse end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_parse') with nowait if exists( select top 1 null from sys.objects where name='sp__script_parse' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_parse] begin try exec dbo.sp_executesql @statement = N'/* Keep this due MS compatibility l:see LICENSE file g:utility r:091128\s.zaglio: added group and continued develop r:090921\s.zaglio: select source code of @obj withhtml t:sp__script_tohtml ''sp__script_tohtml'' */ create proc [dbo].[sp__script_parse] @obj sysname=null, @dbg smallint=0 -- enable print of debug info as begin set nocount on if @dbg>=@@nestlevel exec sp__printf ''level of debugging:%d'',@@nestlevel -- declarations declare @proc sysname, -- for sp__trace @msg nvarchar(4000),-- generic messages @sql nvarchar(4000),-- for inner sql @ret int, -- return ok if 0 error if <0 or a value if >0 @err int, -- user for pure sql statements @i int,@n int, -- generix index variables @timer datetime, -- used to trace times @token sysname, @tl sysname, @p int, @in_comment_line bit, @in_comment bit, @in_string bit, @line nvarchar(4000),@html nvarchar(4000), @step int, @end_declare bit -- close the declaration section so can add -- a new in the middle -- specific declarations; is better keep all on top declare @name sysname -- generic name/string declare @array table (id int identity,name sysname) -- generic list -- initialization select @proc=''sp__script_tohtml'', @ret=0 -- exec sp__elapsed @timer out,''** init of sp__style: '' -- parameters check if @obj is null goto help /* ================================ body ================================== */ -- sp__script create table #src (lno int identity(10,10),line nvarchar(4000)) exec sp__script @obj,@out=''#src'' select @in_comment=0,@in_comment_line=0,@in_string=0,@step=10 select @i=min(lno),@n=max(lno) from #src exec sp__printf ''%s\n%s'','''','''' while (@i<=@n) begin select @line=line from #src where lno=@i select @i=@i+@step -- follows tockens if @line is null exec sp__printf ''
'' else begin select @p=null,@tl=null,@html='''' while (@p is null or (@p!=0 and @p''+@token+'''' else select @html=@html+@tl+coalesce(@token ,'''') -- exec sp__printf ''[%s](%s)'',@tl,@token if @token is null break end -- token scans exec sp__printf ''%s
'',@html end -- if not blank line end -- lines exec sp__printf ''%s\n%s'','''','''' drop table #src goto ret -- end of body /* =============================== errors ================================= */ err: -- init of error management /* ================================ help ================================== */ help: exec sp__usage @proc select @msg=null,@ret=-1 -- generic Help error ret: -- procedure end...is better than return if not @msg is null begin exec sp__printf @msg -- exec sp__trace @msg,@last_id=@ret out,@proc=@proc end return @ret end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_parse: -- ============================================================= sp__script_pkey select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_pkey',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121003 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_pkey') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_pkey') with nowait goto skip_sp__script_pkey end if @ver>121003 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_pkey') with nowait goto skip_sp__script_pkey end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_pkey') with nowait if exists( select top 1 null from sys.objects where name='sp__script_pkey' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_pkey] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:121003\s.zaglio: use of script_synonym v:121002\s.zaglio: script pkey or return list of fields t:sp__script_pkey null,''cfg'',@opt=''flds'',@dbg=1 */ CREATE proc sp__script_pkey @pkey nvarchar(4000) =null out, @obj sysname = null, @sep nvarchar(32) = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common -- @i int,-- @n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options @flds bit,@defs bit, @db sysname, @sql nvarchar(4000), @end_declare bit -- =========================================================== initialization == select @pkey=null, @flds=charindex(''|flds|'',@opt), @defs=charindex(''|defs|'',@opt), @end_declare=1 -- ======================================================== second params chk == if isnull(@obj,'''')='''' goto help if @defs=1 goto err_nos if not parsename(@obj,4) is null goto err_svr -- follow synonym exec sp__script_synonym @obj out,@obj,@opt=''path'' if object_id(@obj,N''U'') is null goto ret -- ===================================================================== body == select @db=isnull(parsename(@obj,3),db_name()) select @sql='' select @pkey=isnull(@pkey+@sep,'''''''')+columnname from [''+@db+'']..fn__script_idx(object_id(@obj,N''''U'''')) where [primary]=1 order by index_column_id '' if @dbg=1 exec sp__printsql @sql exec @ret=sp_executesql @sql, N''@pkey nvarchar(4000) out,@sep nvarchar(32),@obj sysname'', @pkey out,@sep,@obj if @@error!=0 or @ret!=0 goto err_sql if @flds=0 goto err_nos if @dbg=1 exec sp__printf ''-- pkey=%s'',@pkey -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_nos: select @e_msg=''only "flds" option is admitted'' goto err err_sql: select @e_msg=''into inside code'' goto err err_syn: select @e_msg=''cannot follow more than 3 levels of synonyms''goto err err_svr: select @e_msg=''server not admitted in the name'' goto err -- ===================================================================== help == help: exec sp__usage @proc,'' Scope return list of fields of pk of @obj or alter code Parameters @pkey out of list or code @obj is te name of obj; can be a synonym or contain db @sep separator for fields (default is pipe |) @opt options flds list fields separated by @sep defs list definitions (TODO) Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_pkey' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_pkey: -- ============================================================= sp__script_prop select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_prop',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110628 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_prop') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_prop') with nowait goto skip_sp__script_prop end if @ver>110628 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_prop') with nowait goto skip_sp__script_prop end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_prop') with nowait if exists( select top 1 null from sys.objects where name='sp__script_prop' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_prop] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:110628\s.zaglio: added scripting of trigger db v:110406\s.zaglio: removed @out v:100919\s.zaglio: adapted to mssql2k v:100404\s.zaglio: script properties t: exec sp__comment ''[sp__script_prop]'',''test sp..scr..prp'' exec sp__comment ''[sp__script_prop].[@obj]'',''test sp..scr..prp'' exec sp__script_prop ''sp__script_prop'' */ CREATE proc [dbo].[sp__script_prop] @obj sysname=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @obj is null goto help if dbo.fn__isMSSQL2K()=1 begin raiserror(''warning!! sp__Script_prop not compatible with mssql2k'',16,1) goto ret end if @dbg=1 exec sp__printf ''-- sp__script_prop scope'' declare @step int,@type nvarchar(2), @db sysname,@sch sysname,@sch_id int, @obj_ex sysname,@obj_in sysname, @sql nvarchar(4000), @lno_begin int,@lno_end int, @id int declare @src table(lno int identity primary key,line nvarchar(4000)) select @db =parsename(@obj,3), @sch=parsename(@obj,2), @obj=parsename(@obj,1) if @db is null select @db=db_name() select @sch=[name],@sch_id=id from dbo.fn__schema_of(@obj) select @obj_ex=quotename(@db)+''.''+coalesce(quotename(@sch),'''')+''.''+quotename(@obj) select @id=object_id(@obj_ex) if @id is null and dbo.fn__isMSSQL2K()=0 select @id=object_id from sys.triggers where [name]=@obj if @id=0 goto err_nof select @step=ident_incr(''tempdb..#src'') insert @src(line) select ''exec sp__comment ''''''+quotename(@obj)+coalesce(''.''+quotename(column_name),'''')+'''''',''+ ''''''''+replace(convert(nvarchar(4000),[value]),'''''''','''''''''''')+'''''''' from dbo.fn__comments(null) where obj_id=object_id(@obj_ex) if object_id(''tempdb..#src'') is null select line from @src order by lno else insert #src(line) select line from @src order by lno goto ret -- =================================================================== errors == err_nof: exec @ret=sp__err ''object %s not found'',@proc,@p1=@obj_ex goto ret -- ===================================================================== help == help: exec sp__usage @proc select @ret=-1 ret: return @ret end -- sp__script_prop' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_prop: -- =========================================================== sp__script_reduce select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_reduce',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090801 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_reduce') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_reduce') with nowait goto skip_sp__script_reduce end if @ver>090801 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_reduce') with nowait goto skip_sp__script_reduce end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_reduce') with nowait if exists( select top 1 null from sys.objects where name='sp__script_reduce' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_reduce] begin try exec dbo.sp_executesql @statement = N'/* leave this due MS compatibility l:see LICENSE file g:utility v:090801\S.Zaglio:apply some code transformation t: create table #src (lno int identity(10,10),line nvarchar(4000)) create table test_upzcode (id int, c nchar, v nvarchar(12), t ntext,t1[ntext],i int) exec sp__script ''test_upzcode'',@out=''#src'' exec sp__script_reduce 12 -- 4=to unicode+8 print ''-----------------------------------'' exec sp__script ''#src'' -- print output print ''-----------------------------------'' drop table test_upzcode exec sp__recompile ''#src'',@dbg=1 drop table #src drop table test_upzcode */ CREATE proc [dbo].[sp__script_reduce] @normalize tinyint=null, @step int=10, @dbg bit=0 as begin set nocount on declare @sql nvarchar(4000),@msg nvarchar(4000),@proc sysname, @line nvarchar(4000),@i int,@n int,@crlf nchar(2),@j int,@m int, @t datetime,@keywords sysname,@replacers sysname, @replaced sysname,@keyword sysname,@replacer sysname,@exp sysname select @proc=''SP__SCRIPT_REDUCE'' if @normalize is null goto help -- @normalize is used as integer but defined as bit for the future specialization select @crlf=char(13)+char(10) -- delete white lines if (@normalize & 1)=1 delete from #src where line is null -- remove collates and constrains if (@normalize & 2)=2 update #src set line=dbo.fn__RegexReplace(''\s(collate|constraint)\s[^\s]*'','''',line,1,1) -- upsize nvarchar to nvarchar ad ntext to ntext and nchar to nchar if (@normalize & 4)=4 begin set @t=null /* todo: create function fn__word_find(@sentence nvarchar(4000),@word sysname,@lt sysname,@rt sysname) returns int create function fn__word_replace(@sentence nvarchar(4000),@word sysname,@replace sysname,@lt sysname,@rt sysname) returns nvarchar(4000) */ select @keywords=''varchar|char|text'' select @replacers =''(%tkn%,|'' +''(%tkn%)|'' +'' %tkn% |'' +'' %tkn%(|'' +''[%tkn%]|'' +''(%tkn%(|'' +char(9)+''%tkn%(|'' +'' %tkn%,|'' +'' %tkn%)|'' +'' %tkn%''+char(13)+''|'' +char(9)+''%tkn%,'' if @dbg=1 exec sp__elapsed @t out,''-- start convert to unicode:'' select @i=1,@n=dbo.fn__str_count(@keywords,''|''),@m=dbo.fn__str_count(@replacers,''|'') while (@i<=@n) begin select @keyword=dbo.fn__str_at(@keywords,''|'',@i),@i=@i+1 select @j=1 while (@j<=@m) begin select @exp=dbo.fn__str_at(@replacers,''|'',@j),@j=@j+1 select @replacer=replace(@exp,''%tkn%'',@keyword) select @replaced=replace(@exp,''%tkn%'',''n''+@keyword) -- exec sp__printf ''replacer=%s replaced=%s'',@replacer,@replaced update #src set line=replace(line,@replacer,@replaced) end -- while replacers end -- while keywords -- special replacement update #src set line=replace(line,''nvarchar(4000)'',''nvarchar(4000)'') update #src set line=replace(line,''nchar(4000)'',''nchar(4000)'') if @dbg=1 exec sp__elapsed @t out,''-- end in:'' /* it looks like 60 times slower and difficult do find a correct regex update #src set line=dbo.fn__RegexReplace(''(varchar|\[nvarchar])'','' nvarchar '',line,1,1) if @dbg=1 exec sp__elapsed @t out,''-- varchar-->nvarchar:'' update #src set line=dbo.fn__RegexReplace(''(char|\[nchar])'','' nchar '',line,1,1) if @dbg=1 exec sp__elapsed @t out,''-- char-->nchar:'' update #src set line=dbo.fn__RegexReplace(''(text|\[ntext])'','' ntext '',line,1,1) if @dbg=1 exec sp__elapsed @t out,''-- text-->ntext:'' update #src set line=replace(line,'' nvarchar(4000)'','' nvarchar(4000)'') if @dbg=1 exec sp__elapsed @t out,''-- nvc8000-->4000:'' */ end -- remove while line on top and bottom if (@normalize & 8)=8 begin select @i=min(lno),@n=max(lno) from #src while (@i<=@n) begin select @line=coalesce(line,'''') from #src where lno=@i if @line in ('''',@crlf,''GO'') delete from #src where lno=@i else break select @i=@i+@step end while (@n>=@i) begin select @line=coalesce(line,'''') from #src where lno=@n if @line in ('''',@crlf,''GO'') delete from #src where lno=@n else break select @n=@n-@step end end -- normalze 8 -- remove [] if (@normalize & 16)=16 update #src set line=dbo.fn__RegexReplace(''(\[|])'','''',line,1,1) -- go..go if (@normalize & 32)=32 print ''todo'' -- remove go if (@normalize & 64)=64 update #src set line=null where line=''GO'' goto ret help: select @msg =''@normalize can be a mix of:\n'' +''\t1 delete null lines\n'' +''\t2 remove collate and contraint clausees\n'' +''\t4 upsize to unicode data type\n'' +''\t8 remove white line on top and bottom\n'' +''\t16 remove [] parentesis\n'' +''\t64 remove GO lines (not compatible with memory compiling)\n'' exec sp__usage @proc,@extra=@msg select @msg=null ret: if not @msg is null exec sp__printf @msg end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_reduce: -- ========================================================= sp__script_refactor select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_refactor',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100328 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_refactor') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_refactor') with nowait goto skip_sp__script_refactor end if @ver>100328 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_refactor') with nowait goto skip_sp__script_refactor end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_refactor') with nowait if exists( select top 1 null from sys.objects where name='sp__script_refactor' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_refactor] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:100328\s.zaglio: */ create proc sp__script_refactor as begin print ''http://www.dpriver.com/pp/sqlformat.htm'' end -- sp__script_refactor' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_refactor: -- =========================================================== sp__script_review select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_review',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_review') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_review') with nowait goto skip_sp__script_review end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_review') with nowait goto skip_sp__script_review end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_review') with nowait if exists( select top 1 null from sys.objects where name='sp__script_review' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_review] begin try exec dbo.sp_executesql @statement = N'/* leave this v:091018\s.zaglio: help programmer to change code dinamically&sistematically g:utility */ CREATE proc [dbo].[sp__script_review] @old_code sysname=null, @new_code sysname=null, @objs sysname=''%'' as begin -- replace old g: tag -- sp__script_review ''%g:sp__group%''''utility'''',''''%'''''',''%g:utility'' -- add g:tag -- sp__script_review ''%*/'',''%g:utility{crlf}*/'',@objs=''%[_][_]%'' -- sp__script_review ''%exec%sp__elapsed%''''-- SP_SYNC_TABLES:%'''''', -- ''%exec%sp__elapsed%''''-- %s:%'''''',@proc -- sp__script_review ''%exec%sp__printf%''''-- SP_SYNC_TABLES:%'''''', -- ''%exec%sp__printf%''''-- %s:%'''''',@proc print ''programming aid procedure: to do see content'' end--proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_review: -- ============================================================== sp__script_run select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_run',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140108.1506 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_run') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_run') with nowait goto skip_sp__script_run end if @ver>140108.1506 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_run') with nowait goto skip_sp__script_run end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_run') with nowait if exists( select top 1 null from sys.objects where name='sp__script_run' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_run] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:download,web,get,internet v:140108.1506\s.zaglio: moved @dbs before @uri for fast db search v:131215\s.zaglio: @uri -> @src v:131208.0900\s.zaglio: refined load from smb v:130531\s.zaglio: excl. sys dbs and test, removed try-catch r:130529\s.zaglio: added dbs option r:130416\s.zaglio: added alter opt r:130415\s.zaglio: adding unpre opt r:130202\s.zaglio: run a script from @uri t: sp__script_run ''forms|tasks'', ''i:\Documenti\dropbox\PAE\download\utility.sql'' ,@dbg=1 t:sp__script_run ''forms|tasks'',''\\localhost\xch\utility.sql'',@dbg=1 t:sp__script_run ''forms|tasks'',''http://localhost/downloads/utility.sql'',@dbg=1 */ CREATE proc sp__script_run @dbs sysname = null, @src nvarchar(max) = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common -- @run bit, @unpre bit,@alter bit, @crlf nvarchar(2),@cr nchar(1),@lf nchar(1), @i int,@n int,@j int, -- index, counter -- options -- @sel bit,@print bit, -- select and print option for utils @uri nvarchar(1024), @all_db nvarchar(4000), -- option @db sysname, @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), -- @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) -- |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @alter=charindex(''|alter|'',@opt), @crlf=crlf,@cr=cr,@lf=lf, @src=nullif(@src,''''), @uri=ltrim(rtrim(isnull(left(@src,1024),''''))), @db=db_name(), @dbs=nullif(@dbs,''''), @end_declare=1 from fn__sym() if charindex(@cr,@uri)>0 select @uri=left(@uri,charindex(@cr,@uri)-1) -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @dbs is null and @uri is null goto help -- =============================================================== #tbls init == -- ===================================================================== body == select @dbs=isnull(@dbs,@db) select @all_db=isnull(@all_db+'','','''')+name -- select * from sys.databases cross apply fn__str_table(replace(@dbs,'','',''|''),''|'') where name like token and not name in (''master'',''tempdb'',''model'',''msdb'',''Resource'',''Distribution'') and left(name,12)!=''ReportServer'' order by name /* t:sp__script_run ''%'' t:sp__script_run ''forms,ruler,tasks'', ''I:\Documenti\dropbox\PAE\download\utility.sql'',@dbg=1 t:sp__script_run ''forms,ruler,tasks,xx'' */ if (isnull(@all_db,'''')!='''' and @all_db!=@db) or @dbg>0 exec sp__printf ''-- to execute on:\n%s'',@all_db if isnull(@all_db,'''')='''' raiserror(''no dbs found'',16,1) if dbo.fn__str_count(@all_db,'','')0 begin if @dbg>0 exec sp__printf ''-- getting via web'' exec sp__web @uri,@rsp=@src out,@rcq=''get'' if charindex(''
'',@src)>0
    and (charindex(''/>'',@src)>0 or charindex(''
'',@src)>0) select @unpre=charindex(''|unpre|'',@opt) -- select @src=replace(@src,@crlf+@crlf,@crlf) if @unpre=1 begin /* sp__script_run ''http://xoomer.virgilio.it/stezagl/io/eng/my_works/source/sp_source/code_sql/fn__at.htm'', @dbg=1,@opt=''unpre|alter'' */ select @i=charindex(''
'',@src,@i),@i=@j+1
        select @j=charindex(''
'',@src) select @src=substring(@src,@i,@j-@i) while left(@src,1) in (@cr,@lf) select @src=substring(@src,2,len(@src)) while right(@src,1) in (@cr,@lf) select @src=left(@src,len(@src)-1) end select @uri=null end -- file /uri) path to windows path if left(@uri,8)=''file:///'' select @uri=replace(substring(@uri,9,1024),''/'',''\'') if patindex(''%:%\%'',@uri)>0 or left(@uri,2)=''\\'' begin if @dbg>0 exec sp__printf ''-- reading file %s'',@uri -- not the faster but read 2MB in 7 seconds on localmachine select @src='''' exec sp__file_read_stream @uri,@out=@src out -- sp__file_read_stream ''I:\Documenti\web_sites\PAE\download\utility.sql'' select @n=len(@src) if @dbg>0 exec sp__printf ''-- loaded %d chars'',@n select @uri=null end if @alter=1 begin select @i=charindex(''create function'',@src) if @i=0 select @i=charindex(''create proc'',@src) if @i=0 select @i=charindex(''create procedure'',@src) if @i=0 select @i=charindex(''create view'',@src) if @i>0 select @src=left(@src,@i-1)+''alter ''+substring(@src,@i+7,len(@src)) end -- ########################## -- ## -- ## execute script -- ## -- ######################################################## if @src is null goto err_ems -- if is a direct code if not @uri is null begin -- remove initial returns while left(@src,1) in (@cr,@lf) select @src=stuff(@src,1,1,N'''') -- encapsulate select @src=''exec(''''''+replace(@src,'''''''','''''''''''')+'''''')'' end if @dbg>0 exec sp__printsql @src declare cs cursor local for select token from fn__str_table(@all_db,'','') open cs while 1=1 begin fetch next from cs into @db if @@fetch_status!=0 break if (isnull(@dbs,'''')!='''' and @dbs!=@db) or @dbg>0 exec sp__printframe ''updating %s'',@db if @dbg=0 begin exec(''use [''+@db+'']''+@crlf+@src) end else exec sp__printf ''use [%s] ...'',@db end -- cursor cs close cs deallocate cs -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope load a script from a file or a url or a remote server or a contant and execute it on local db or on multiple dbs Parameters @dbs multi like expression separated by comma or pipe where run the script @src can be the source code of script or the path of the file or web address %:% or %\% or file:///% is a file \\% or %:%@\\% is a smb file (not yet supported) ftp://[usr:pwd@]... is a ftp file (not yet supported) @opt options alter replace create function/view/proc with alter @dbg debug level 1 show basic info and do not execute the script Examples sp__script_run "%" -- list all dbs (w.out sys.dbs) sp__script_run "%tst%|%bak%" -- list all dbs that likes tst or bak -- run script.sql in all selected dbs sp__script_run "%tst%|%bak%","c:\script.sql" -- get the script from internet and run into local db sp__script_run @src="http\\site.com\utility.sql" -- run constant script over all (non system) dbs sp__script_run "%","select db_name()" '' select @ret=-1 goto ret -- =================================================================== errors == err_ems: exec sp__err ''empty script'',@proc goto ret -- ===================================================================== exit == ret: return @ret end -- proc sp__script_run' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_run: -- =========================================================== sp__script_select select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_select',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130518 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_select') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_select') with nowait goto skip_sp__script_select end if @ver>130518 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_select') with nowait goto skip_sp__script_select end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_select') with nowait if exists( select top 1 null from sys.objects where name='sp__script_select' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_select] begin try exec dbo.sp_executesql @statement = N'/* Leave this unchanged doe MS compatibility l:see LICENSE file g:utility,script v:130518\s.zaglio: select objects for scripting purpose t:sp__script_select ''utility'',@dbg=1 t:sp__script_select ''utility'' n:https://code.google.com/p/jquerycsvtotable/ n:http://tablesorter.com/docs/ */ CREATE proc [dbo].sp__script_select @grps_objs nvarchar(4000) =null, @exclude sysname =null, @include sysname =null, @opt sysname =null, @dbg int =0 as begin try set nocount on declare @proc sysname,@ret int, @e_msg nvarchar(4000),@e_p1 sysname,@e_p2 sysname, @i int,@aut sysname -- derived parameter select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(coalesce(@opt,''''),''|'') -- ================================================================ param chk == if @grps_objs is null goto help if charindex(''|@'',@opt)>0 select @aut=dbo.fn__str_between(@opt,''|@'',''|'',default) -- ============================================================= declarations == if object_id(''tempdb..#info'') is null -- this table will contain all objects to script create table #info ( obj_id int,obj sysname,tag nvarchar(4), val1 nvarchar(4000),val2 nvarchar(4000),val3 nvarchar(4000) ) if object_id(''tempdb..#grp_objs'') is null create table #grp_objs( obj_id int null, obj sysname, xt nvarchar(2) null, tag nvarchar(16) default(''v''), aut sysname, ver nvarchar(16) null, [des] sysname null, grp1 sysname null default(''''), grp2 sysname null default(''''), grp3 sysname null default(''''), core bit default(0), -- basic obj used to define others [drop] sysname null, ord int, match bit, ) -- ===================================================================== body == -- groups insert #info(obj_id,obj,tag,val1,val2,val3) select obj_id,obj,tag, cast(val1 as nvarchar(4000)), cast(val2 as nvarchar(4000)), cast(val3 as nvarchar(4000)) from dbo.fn__script_info(null,''g'',default) select ''grps'' tbl,* from #info -- apply group filter if charindex('','',@grps_objs)>0 delete obj from #info obj join dbo.fn__str_table(@grps_objs,'','') fil on not token in (obj.val1,obj.val2,obj.val3) where obj.tag in (''v'',''r'') select ''grps filtered'' tbl,* from #info -- deprecated insert #info(obj_id,obj,tag,val1,val2,val3) select obj_id,obj,tag, cast(val1 as nvarchar(4000)), cast(val2 as nvarchar(4000)), cast(val3 as nvarchar(4000)) from dbo.fn__script_info(null,''d'',default) select ''deprecated'' tbl,* from #info where tag=''d'' -- version or release insert #info(obj_id,obj,tag,val1,val2,val3) select obj_id,obj,tag, cast(val1 as nvarchar(4000)), cast(val2 as nvarchar(4000)), cast(val3 as nvarchar(4000)) from dbo.fn__script_info(null,''vr'',0) select ''vr'' tbl,* from #info where tag in (''v'',''r'') -- apply objects filter if charindex(''|'',@grps_objs)>0 delete obj from #info nfo where nfo.tag in (''r'',''v'') and nfo.obj in (select token from dbo.fn__str_table(@grps_objs,''|'')) select ''vr filtered'' tbl,* from #info where tag in (''v'',''r'') -- remove deprecated delete vr from #info vr join #info d on vr.obj=d.obj where vr.tag in(''v'',''r'') and d.tag=''d'' select ''vr - deprecated'' tbl,* from #info where tag in (''v'',''r'') if @dbg>1 select * from #info -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope select objects to script; used by sp__script_group or other utility Parameters @grps_objs single group to script * the group is identified by tag G: * tag G support multiple groups separated by comma (",") * if contain a %, select names instead of group * if contain *, select also tables (with idxs,fkeys,trs) * SYS group, script S objects from fn__script_sysobjs * obj1|obj2|... direct script only obj1,obj2,... * grp1,grp2,... script objs that belongs to grp1 or ... @out can be a path where out a single file or multiple files (extension is .sql or .htm depending on @opt) %grp% will be replaced with group name and create a unique file %obj% will replaced with obj name and create multiple files %t will be replaced with YYMMDD_HHMMSS %temp% will be replaced with windows user temp directory @opt options html out as html (if out to multiple files, an index.htm will be created) prefix:path prefix path to link in index.html (prefix:./code_sql/) nochk do not add check version bin return results as compressed binary string @user filter of objects of "user" @dbg 1 list selected objects and exit 2 print and do not out to files @exclude is a "like" expression for post exclusion of objects @include is a "like" expression for pre inclusion of objects Notes * an object that end with group name and "_setup", is considered the setup store procedure of the group, scripted 1st and executed immediatelly * if sp__script_store and sp__script_group are in R tag, cannot script * if object "%_%groupname%_setup" is in R, scripting is aborted Examples -- normal use exec sp__script_group ''''utility'''' -- special out to file with html format and index exec sp__script_group ''''script'''',@out=''''%temp%\%obj%'''',@opt=''''index'''' -- replace macros create table #vars (id nvarchar(16),value nvarchar(4000)) insert #vars select ''''%license%'''',''''test replacements'''' exec sp__script_group ''''script'''' drop table #vars ########################## ## ## SCRIPT GROUP STEPS ## ================== ## ## if script to console or into single file: ## drop deprecated objects ## check version ## drop object ## re-create ## ## is script "utility" group: ## if exists uninstall db trigger ## eventually re-create scripting core objects ## drop deprecated objects ## check version ## drop object ## re-create ## if exists install db trigger and upgrade if necessary ## ######################################################## '' select distinct grp grps from ( select val1 grp from #info nfo where nfo.tag=''g'' union select val2 grp from #info nfo where nfo.tag=''g'' union select val3 grp from #info nfo where nfo.tag=''g'' ) grps where not grp is null order by 1 select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_select' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_select: -- ======================================================== sp__script_sign_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_sign_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131123 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_sign_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_sign_test') with nowait goto skip_sp__script_sign_test end if @ver>131123 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_sign_test') with nowait goto skip_sp__script_sign_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_sign_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_sign_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_sign_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131123\s.zaglio: adapted to new fn__script_sign v:130923\s.zaglio: added help of fn__Script_sign v:130730,130729\s.zaglio: test fn__script_sign t:select dbo.fn__script_sign(''fn__script_info_tags'',null) -- 105529698.0000 t:select dbo.fn__script_sign(''fn__script_info_tags'',1) -- 131129.0000 t:select dbo.fn__script_sign(''fn__script_info_tags'',4) -- 1796022540.0000 t:select dbo.fn__script_sign(''fn__script_info_tags'',8) -- 105529698.0000 */ CREATE proc sp__script_sign_test as begin set nocount on declare @ret int,@proc sysname select @ret=0,@proc=object_name(@@procid) declare @id int,@obj sysname,@detail tinyint, @result numeric(14,4),@des sysname, @new_result numeric(14,4),@st sysname declare @t table( id int, obj sysname, detail tinyint, result numeric(14,4), des sysname ) insert @t select 1,''tst_fn__script_sign'',null,141296445.0000,''rows only(!)'' union select 2,''tst_fn__script_sign'',1,755913805.0000,''with idx'' union select 3,''tst_fn__script_sign'',4,2136238363.0000,''as (!)-names'' union select 4,''tst_fn__script_sign'',8,577207619.0000,''with charset&collate'' union select 5,''sp__script_sign_test'',null,0.0000,''header'' union select 6,''sp__script_sign_test'',1,131123.0000,''body'' union select 7,''sp__script_sign_test'',4,0.0000,''types only'' union select 8,''sp__script_sign_test'',8,0.0000,''with charset&collate'' union select 9,''fn__script_sign_test'',null,974999305.0000,''header'' union select 10,''fn__script_sign_test'',1,131123.0000,''body'' union select 11,''fn__script_sign_test'',4,443965265.0000,''types only'' union select 12,''fn__script_sign_test'',8,974999305.0000,''with charset&collate'' exec sp__printf ''-- test fn__script_sign correct results'' if not object_id(''tst_fn__script_sign'') is null drop table tst_fn__script_sign exec('' create table tst_fn__script_sign( a int, b sysname collate Latin1_General_CI_AS null ) create index ix_tst_fn__script_sign_a on tst_fn__script_sign(a) '') if not object_id(''fn__script_sign_test'') is null drop function fn__script_sign_test exec(''/* leave this v:131123\s.zaglio: test creation */ create function fn__script_sign_test(@a int, @b sysname) returns table as return select cast(1 as int) as a,cast(''''b'''' as sysname) as b union select @a,@b '') declare cs cursor local for select id,obj,detail,result,des from @t open cs while 1=1 begin fetch next from cs into @id,@obj,@detail,@result,@des if @@fetch_status!=0 break select @new_result=dbo.fn__script_sign(@obj,@detail) if @new_result=@result select @st=''ok'' else select @st=''ko'' exec sp__printf ''test %d:%s, %s, expected:%s, given:%s'', @id,@st,@obj,@result,@new_result if @st=''ko'' select @ret=1 end -- cursor cs close cs deallocate cs if not object_id(''tst_fn__script_sign'') is null drop table tst_fn__script_sign if not object_id(''fn__script_sign_test'') is null drop function fn__script_sign_test if @ret!=0 exec @ret=sp__err ''test failed'',@proc exec sp__printf '''' exec sp__usage @proc,'' Scope test fn__script_sign and give help for fn Parameters @obj name of object @detail specification of what it calculate the signature * details for table/sp/fn/views bit_val meaning 0/null table columns or params of sp/fn, without defaults 1 table columns with index or params of sp/fn with body 2 table columns or params of sp/fn without names, without defaults 4 table columns with index or params of sp/fn without names 8 same as previous with charset&collate info * details for jobs 0/null names/status of jobs 1 names/status of jobs with names,commands,flags,outfile of steps 2 status of jobs 6 status of jobs with commands,flags,outfile of steps without names '' return @ret end -- sp__script_sign_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_sign_test: -- ============================================================ sp__script_store select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_store',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131006.1200 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_store') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_store') with nowait goto skip_sp__script_store end if @ver>131006.1200 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_store') with nowait goto skip_sp__script_store end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_store') with nowait if exists( select top 1 null from sys.objects where name='sp__script_store' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_store] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:131006.1200\s.zaglio:refactor and changed data to store v:131002.1100,131001\s.zaglio:better messages;test for more dependant objs v:130908;130731.1000\s.zaglio:warning "in the future";changed newer/older warning v:130712\s.zaglio:disable test of 130604 on alter v:130606\s.zaglio:improved warning on test of bad v-r tags v:130604\s.zaglio:test for more than 2 months older release v:130317;120919\s.zaglio:a bug near fn__context_info use;tested script_act v:120906;120905\s.zaglio:around script_act;added refer to "script_act" v:120823;120731\s.zaglio:added chk if not complete header and dis,dbg options,#!@msg_fl r:120724;120523\s.zaglio:about messages;removed range 0-65535 and tested future release v:120518.1800\s.zaglio:adapted to new fn__script_sysobjs v:120509;120503\s.zaglio:about help and debug;adopted skip of range 0-65535 and uppers v:120223;1140;120213\s.zaglio: a overflow near release;adapted to new fn__script_events v:120208;120207\s.zaglio:replaced identity;adapting to new log_ddl v:120126;111205\s.zaglio:reversed means of @msg option,added context info comunication v:110921;110824\s.zaglio:added skip of maintenance code and trim;removed use of try/c. v:110624\s.zaglio:log_ddl.id is no longer a progressive and utcdate v:110622\s.zaglio:modified host separator \ with _ v:110621\s.zaglio:added msg for every store and more help v:110527\s.zaglio:added exclusions of sysobjs_ and _sysobjs v:110510;110504\s.zaglio:added specific skips;added chk of diff. users v:110418;110415\s.zaglio:added skip of utilities;adapted to log_ddl v:110325;110324\s.zaglio:add check of tids and flags;better msg, no prop.if same ver v:110323.1818;110323\s.zaglio:add ver. overwr. test;exclus. of some event from test v:110322;110321\s.zaglio:added release;called by tr__script_trace_db t:sp__script_trace t:sp__script_history */ CREATE proc sp__script_store @et sysname = null, -- event type @obj sysname = null, @sql nvarchar(max) = null, @opt sysname = null, -- if called by command line @dbg int = null as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on declare @proc sysname, @err int, @ret int,@no_opt varchar(1) select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), @no_opt='''' -- dependencies test if @obj=''fn__script_info_tags'' goto ret if @obj=''log_ddl'' and @et=''drop_table'' goto err_tbl if object_id(''tids'') is null or object_id(''fn__sym'') is null or object_id(''fn__crc16'') is null or object_id(''fn__str_quote'') is null or object_id(''fn__context_info'') is null or object_id(''fn__servername'') is null or object_id(''fn__script_info_tags'') is null or object_id(''flags'') is null or object_id(''log_ddl'') is null or object_id(''fn__script_sysobjs'') is null goto wrn_dep select @opt=case when @opt is null then @no_opt else dbo.fn__str_quote(@opt,''|'') end -- ########################## -- ## -- ## transaction into try/catch into trigger -- ## -- ######################################################## /* begin try save tran ... begin tran ... unfortunatelly into a trigger any form of sub transaction is not possibile because rollback automatically even if the error is managed The procedure must be perfect! */ -- ================================================================= declares == declare @time datetime, @ms int, -- milliseconds @i int, -- index var @tmp nvarchar(max), @eq_body bit, -- @udt datetime, -- last update time @flags smallint, @fver smallint, @pvft bit, -- has version header @srv sysname, @app nvarchar(256), @usr nvarchar(256), @host nvarchar(256), @prev_usr nvarchar(256), @cmt nvarchar(4000), @id int, @start_id int, @counter_id int, @app_id int, @usr_id int, @host_id int, @event_id int, @obj_id int, @db_id int, @srv_id int, @parent_id int, -- hashes for faster search @app_hash int, @usr_hash int, @obj_hash int, @host_hash int, @db_hash int, @srv_hash int, -- type of records (tids) @tcnt tinyint, @tsql tinyint, @tdb tinyint, @tusr tinyint, @tobj tinyint, @tapp tinyint, @tsrv tinyint, @tev tinyint, @thost tinyint, /* log_ddl content (select * from log_ddl) tid rid pid txt rel flags ======= =========== =========== =============== =============== ====== cnt last id "id counter" svr 0 0 svr name db svr id 0 db name obj db id 0 obj name sql obj_id host id code last release flg.ver host svr id host name usr host id 0 usr name app host id app name */ @tag nchar(1), -- tag R or V @db sysname, @rel bigint, @old bigint, @old_flags smallint, @today_rel int, -- calc. from date @dt datetime, -- to calc cur_rel @prev_usr_id int, @hh nvarchar(32), @mi nvarchar(32), @info sysname, -- session config @msg_fl smallint, @msg nvarchar(1024), @moff sysname,@mon sysname, -- msg on/off codes ... @dis sysname, -- disable @dbgswc sysname, -- debug switch @et_cmd nvarchar(32), -- right split of @et @et_cmd_typ nvarchar(32), -- left split of @et -- options @opt_dbg bit, -- switch debug mode on/off @opt_dis bit, -- disable store @opt_ena bit, -- enable store @opt_moff bit, -- message off @opt_mon bit, -- message on @opt_mdef bit, -- only system messages -- debug info @dbg_nfo1 sysname, @dbg_nfo2 sysname, @dbg_nfo3 sysname, @dbg_nfo4 sysname, @end_declare bit -- ===================================================================== init == select @time =getdate(), @dis =@proc+'':disable'', @dbgswc=@proc+'':debug'', @mon =@proc+'':message_on'', @moff =@proc+'':message_off'', @msg_fl=case when dbo.fn__context_info(@mon)>0 then 1 when dbo.fn__context_info(@moff)>0 then -1 -- OFF win on ON else 0 end -- options if @opt!=@no_opt select @opt_dbg = charindex(''|dbg|'',@opt), @opt_dis = charindex(''|dis|'',@opt), @opt_ena = charindex(''|ena|'',@opt), @opt_moff = charindex(''|moff|'',@opt), @opt_mon = charindex(''|mon|'',@opt), @opt_mdef = charindex(''|mdef|'',@opt) -- debug info if @dbg=1 select @dbg_nfo1=''@tag=%s, @flags=%s, @tmp=%s'', @dbg_nfo2=''@hh=%s,@mi=%s,@rel=%s,@cur=%s'', @dbg_nfo3=''tag=%s,rel=%s,usr=%s'', @dbg_nfo4=''typ=%s, obj=%s, hast=%d, pid=%d'' -- ========================================================= param formal chk == if (@et is null or @obj is null or @sql is null) begin if @opt!=@no_opt begin if @opt_dbg=1 begin -- debug on/off if dbo.fn__context_info(@dbgswc)>0 begin exec sp__context_info @dbgswc,@opt=''del'' print @proc+'': debug disabled'' end else begin exec sp__context_info @dbgswc print @proc+'': debug enabled'' end end if @opt_dis=1 begin -- disable exec sp__context_info @dis end if @opt_ena=1 begin -- enable exec sp__context_info @dis,@opt=''del'' end if @opt_moff=1 begin -- system and normal messages off exec sp__context_info @mon,@opt=''del'' exec sp__context_info @moff end if @opt_mon=1 begin -- all messages on exec sp__context_info @moff,@opt=''del'' exec sp__context_info @mon end if @opt_mdef=1 begin -- default: print only system messages and when obj has tag exec sp__context_info @mon ,@opt=''del'' exec sp__context_info @moff,@opt=''del'' end goto ret end goto help end -- no params given -- check for particular situation that skip store of script if dbo.fn__context_info(@dbgswc)>0 and @dbg=0 select @dbg=1 if dbo.fn__context_info(@dis)>0 goto ret select @sql=ltrim(rtrim(@sql)) select @tmp=left(@sql,512) if charindex(''[%group%]'',@tmp)>0 goto err_hdr if charindex(''[%keywords%]'',@tmp)>0 goto err_hdr if patindex(''%\[%]%[%]:%'',@tmp)>0 goto err_hdr -- skip specific maintenance if @sql like ''ALTER INDEX % REORGANIZE WITH %'' goto ret -- skip MSOffice and specific application or system obj -- select * from dbo.fn__script_sysobjs((select obj from tids)) if len(@obj)=3 goto ret -- generically the sys obj are or 3 letters if left(@obj,3) in (''dt_'') goto ret if @dbg=1 begin raiserror(@proc,10,0) with nowait print ''obj:''+isnull(@obj,''???'') print ''sql:''+isnull(@sql,''???'') end select @start_id= power(-2,31), @dt= getdate(), @today_rel= cast(convert(sysname,@dt,12)+ left(replace(convert(sysname,@dt,8),'':'',''''),4) as int ), @tcnt= 1, @tsrv= tids.srv, @tdb= tids.db, @tusr= tids.usr, @tapp= tids.app, @tsql= tids.code, @tobj= tids.obj, @tev= tids.ev, @thost= tids.host, @flags= 0, @srv= upper(dbo.fn__servername(null)), @db= upper(db_name()), @app= upper(left(app_name(),256)), @host= upper(left(system_user+''@''+host_name(),256)), @usr= null, @obj= upper(@obj), @srv_hash=dbo.fn__crc32(@srv), @db_hash =dbo.fn__crc32(@db), @app_hash=dbo.fn__crc32(@app), @obj_hash=dbo.fn__crc32(@obj), @host_hash=dbo.fn__crc32(@host), @fver= flg.ver, @i=charindex(''_'',@et), @et_cmd = left(@et,@i-1), @et_cmd_typ = substring(@et,@i+1,128), @pvft= case -- has version header when @et_cmd_typ in (''proc'',''view'',''function'',''trigger'') then 1 else 0 end, @udt= getutcdate() from tids,flags flg -- excludes system objects derivated (prefix, postfix, same) if exists( select top 1 null from dbo.fn__script_sysobjs(@tobj) where cod+''_''=left(@obj,4) or ''_''+cod=right(@obj,4) or cod=@obj ) goto ret -- ============================================= check header and old version == select @tmp=null select top 1 @tag=tag, @tmp=convert(nvarchar,val1), @usr=convert(nvarchar,val2), @cmt=convert(nvarchar,val3) from dbo.fn__script_info_tags(@sql,''rv'',0) if not @tag is null and @msg_fl!=-1 select @msg_fl=1 if @tag=''v'' or @tag is null select @flags=@flags|@fver if @tag in (''r'',''v'') and (isnull(@usr,'''')='''' or isnull(@cmt,'''')='''') goto err_hdr -- if @cmt='''' -- no comment or omitted author if @dbg=1 exec sp__printf @dbg_nfo1,@tag,@flags,@tmp select @msg='''' if @tmp is null begin if @pvft=1 begin -- print dbo.fn__str_at(''alter proc'','''',2) select @msg=''no release info in "''+@obj+''"'' end end else begin select @i=charindex(''.'',@tmp) if @i=0 select @mi=''0000'',@hh=@tmp else select @hh=substring(@tmp,1,@i-1), @mi=right(''0000''+substring(@tmp,@i+1,32),4) if len(@hh)!=6 select @msg=''wrong version near "%tmp%"'' else begin if @hh+@mi like ''%[^0-9]%'' select @msg=''bad release number near "%tmp%"'' else begin select @rel=cast(@hh+@mi as bigint) if @dbg=1 exec sp__printf @dbg_nfo2,@hh,@mi,@rel,@today_rel if @rel>2147483648 goto err_int if @rel>@today_rel select @msg=''obj version of "%tmp%" is in the future'', @tmp=@obj if @et_cmd=''alter'' begin declare @nrel float select @nrel=abs(@rel-@today_rel) if (@nrel>2000000) -- two months select @msg=''obj "%tmp%" newer or older than 2 months'', @tmp=@obj end -- if @et_cmd= end -- if ok yymmdd end -- if good release info end -- if not @tmp/src is null if @msg_fl=1 and @msg!='''' print @proc+'':WARNING:''+replace(@msg,''%tmp%'',@tmp) if @dbg=1 exec sp__printf @dbg_nfo3,@tag,@rel,@usr -- notes: when CATCH is released, error 3930 occur -- ================================================= get/store srv/db/usr nfo == -- do not store utilities like sp__, fn__, ix__, ... if substring(@obj,3,2)=''__'' goto ret select @counter_id=case when l.tid=@tcnt then id else @counter_id end, @srv_id= case when l.tid=@tsrv then id else @srv_id end, @db_id = case when l.tid=@tdb then id else @db_id end from log_ddl l where l.tid in (@tsrv,@tdb,@tcnt) if @counter_id is null begin select @counter_id=@start_id insert log_ddl(srv,id,tid,rid,pid,flags,txt,dt,[key]) select @counter_id, @counter_id, 1,@counter_id+3, 0, 0, ''id counter'', @udt, 0 end if @srv_id is null begin select @srv_id=@start_id+1 insert log_ddl(srv,id,tid,rid,pid,flags,txt,dt,[key]) select @srv_id, @srv_id, @tsrv, 0, 0 as flags, 0, @srv, @udt, @srv_hash end if @db_id is null begin select @db_id=@start_id+2 insert log_ddl(srv,id,tid,rid,pid,flags,txt,dt,[key]) select @srv_id, @db_id, @tdb, @srv_id, 0, 0, @db, @udt, @db_hash end -- search or insert host_id select @host_id=id from log_ddl [log] -- with (index(ix_log_ddl_key)) where srv=@srv_id and tid=@thost and [key]=@host_hash and [log].skey=@host and rid=@srv_id if @host_id is null begin update log_ddl with (updlock) set @host_id=rid=rid+1 where id=@counter_id insert log_ddl(srv,tid,id,rid,pid,flags,[key],txt,dt) select @srv_id,@thost,@host_id,@srv_id,0,0,@host_hash,@host,@udt end -- search obj_id select @obj_id=id from log_ddl [log] -- with (index(ix_log_ddl_key)) where srv=@srv_id and tid=@tobj and [key]=@obj_hash and [log].skey=@obj and rid=@db_id if @obj_id is null begin update log_ddl with (updlock) set @obj_id=rid=rid+1 where id=@counter_id insert log_ddl(srv,tid,id,rid,pid,flags,[key],txt,dt) select @srv_id,@tobj,@obj_id,@db_id,0,0,@obj_hash,@obj,@udt end -- ================================================= compare with old version == select @event_id=id from fn__script_sysobjs(@tev) ev where ev.cod=@et -- read last occurrence of same obj -- sp__script_trace select top 1 @old_flags=flags, @eq_body=case when @sql=txt then 1 else 0 end, @old=rel, -- rel/ver @prev_usr_id=pid from log_ddl [log] -- with (nolock,index(ix_log_ddl_key)) where srv=@srv_id and tid=@tsql and [key]=@obj_hash and rid=@obj_id order by dt desc -- update log_ddl set c5=1103221000,rid=1234 where id=7 -- delete from log_ddl where id=9 if @old>@rel and @msg_fl=1 begin select @msg=@proc+'': WARNING :probable version conflict''+char(13) +''this '' +substring(cast(@rel as nvarchar),1,6)+''.'' +substring(cast(@rel as nvarchar),7,4) +''is older than previous '' +substring(cast(@old as nvarchar),1,6)+''.'' +substring(cast(@old as nvarchar),7,4) +'' use sp__script_diff @obj to see differences'' print @msg end else begin if (@prev_usr_id!=@usr_id) and @msg_fl=1 begin select top 1 @prev_usr=txt from log_ddl where id=@prev_usr_id select @msg=@proc+'': WARNING :previously changed by user "'' +isnull(@prev_usr,''(unk)'')+''".'' +'' Use sp__script_diff @obj to see differences.'' print @msg end end -- prev_host select @eq_body=isnull(@eq_body,0), -- if is new: @old_flags=isnull(@old_flags,0) -- is a release if @old=@rel -- if version/release number is equal and @old_flags&@fver=@fver -- and prev. store is a ver. and not a rel. and @eq_body=0 -- but bodies are different and @flags&@fver=@fver -- and the new body is a version too, if @msg_fl=1 begin select @msg=@proc+ +'':WARNING:same version with different body will '' +''not be distributed'' print @msg end if @eq_body != 0 goto ret -- ====================================================== store reference ids == -- search or insert usr_id if @usr is null -- if drop ... try to go back to usr from host begin select @usr_id=id,@usr=skey from log_ddl [log] -- with (index(ix_log_ddl_key)) where srv=@srv_id and tid=@tusr and rid=@host_id if @@rowcount=0 select @usr_id=@host_id end else begin select @usr_hash=dbo.fn__crc32(@usr) select @usr_id=id from log_ddl [log] -- with (index(ix_log_ddl_key)) where srv=@srv_id and tid=@tusr and [key]=@usr_hash and [log].skey=@usr and rid=@host_id if @usr_id is null begin update log_ddl with (updlock) set @usr_id=rid=rid+1 where id=@counter_id insert log_ddl(srv,tid,id,rid,pid,flags,[key],txt,dt) select @srv_id,@tusr,@usr_id,@host_id,0,0,@usr_hash,@usr,@udt end end -- search or insert app -- app info are stored as stand alone select @app_id=id from log_ddl [log] -- with (index(ix_log_ddl_key)) where srv=@srv_id and tid=@tapp and [key]=@app_hash and [log].skey=@app and rid=@host_id if @app_id is null begin update log_ddl with (updlock) set @app_id=rid=rid+1 where id=@counter_id insert log_ddl(srv,tid,id,rid,pid,flags,[key],txt,dt) select @srv_id,@tapp,@app_id,@host_id,0,0,@app_hash,@app,@udt end -- ==================================================================== store == update log_ddl with (updlock) set @id = rid = rid+1 where id=@counter_id insert log_ddl( srv,tid,id,rid,pid,flags, [key],txt,ev,rel,dt ) select @srv_id,@tsql,@id,@obj_id,@usr_id,@flags, @obj_hash,@sql,@event_id,@rel,@udt select @i=@@rowcount -- select @id=lid from log_ddl where id=@id select @ms=datediff(ms,@time,getdate()) if @msg_fl=1 print @proc+'': "''+@obj+''" computed and stored in ''+convert(sysname,@ms) +''ms with id '' +substring(dbo.fn__hex(@id),3,8) +'' on [''+@db+'']. See SP__SCRIPT_HISTORY.'' -- application triggers if not object_id(''script_act'') is null begin /* if is an index (todo:rule & constraint), search for parent */ if @et_cmd_typ=''index'' begin -- unfortunatelly drop index is not catched because -- do not exists anymore select @parent_id=object_id from sys.indexes where name=@obj select @obj=name,@obj_hash=dbo.fn__crc32(upper(name)) from sys.objects o where object_id=@parent_id end if @dbg=1 exec sp__printf @dbg_nfo4,@et_cmd_typ,@obj,@obj_hash,@parent_id select @sql=null select @sql=isnull(@sql+char(13),'''')+txt from script_act where pid=@obj_hash order by idx if isnull(@sql,'''')!='''' begin exec(@sql) -- use of try-catch will rollback all in case of error if @@error!=0 exec sp__printsql @sql end end /* removed because sqlagent errors if not object_id(''sp__script_sync'') is null exec sp__script_sync @opt=''run'' */ goto ret -- =================================================================== errors == err_tbl: raiserror(''before drop this table, disable trace db trigger'',11,1) rollback err_int: select @msg=''release out of range (>214748.3648).''+ ''Your TSQL was executed but not stored.'' raiserror (@msg,11,1) goto ret err_rel: select @msg=''obj %s compiled but not stored because ''+ ''you specified a version in the future or 2 months older:''+ '' %s.%s VS %d'' raiserror(@msg,11,1,@obj,@hh,@mi,@today_rel) goto ret err_hdr: select @msg=''WRONG HEADER: missing AUTHOR or COMMENT in tag R,V '' +''or %%group%%, %%keywords%%.'' raiserror (@msg,11,1) rollback goto ret wrn_dep: print @proc+'': WARNING :not executed because a base utility is absent.'' goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope Called by tr__trace or sp__trace_event, store info about DDL event in table LOG_DDL. Called by sp__script_history, store info about DML event in table LOG_DDL. Notes * Show only messages when object has tags. See MOFF,MDEF options. * if a reference is present into "script_act", do that action. (this is like a trigger related to any action about an object) Parameters @et see db trigger @obj see db trigger @sql see db trigger @opt options moff hide all messages mon show all messages mdef reset to default dis disable the store in case of inside error ena re/enable the store dbg enable debug info '' -- check for foundamental objects presence select @i=1,@tmp=''tids|flags|log_ddl|fn__script_sysobjs'' while 1=1 begin select @obj=dbo.fn__str_at(@tmp,''|'',@i),@i=@i+1 if @obj is null break if object_id(@obj) is null exec sp__printf ''WARNING:%s is a foundamental object'',@obj end exec sp__printf '' List prefix,postfix or object name that will be excluded by this sp '' select @tobj=obj from tids exec sp__select_astext ''select cod as sysobj from dbo.fn__script_sysobjs({1})'', @header=0,@p1=@tobj select @ret=-1 ret: return @ret end -- drop proc sp__script_store' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_store: -- ============================================================= sp__script_sync select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_sync',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110418 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_sync') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_sync') with nowait goto skip_sp__script_sync end if @ver>110418 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_sync') with nowait goto skip_sp__script_sync end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_sync') with nowait if exists( select top 1 null from sys.objects where name='sp__script_sync' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_sync] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,trace r:110418\s.zaglio: added check of presence of utils r:110321\s.zaglio: syncronize new updates */ CREATE proc sp__script_sync @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) -- check if utilities are regenerating if object_id(''fn__str_quote'') is null goto ret if object_id(''sp__isjob'') is null goto ret if object_id(''fn__config'') is null goto ret if object_id(''sp__config'') is null goto ret if object_id(''sp__job'') is null goto ret select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == declare @ok int -- xp_cmdshell ''type C:\DOCUME~1\NETWOR~1\IMPOST~1\Temp\utility_sp__script_sync_log.txt'' exec @ok=sp__isjob @@spid,@dbg=0 -- select @ok=dbo.fn__isjob(@@spid) if @ok=1 goto sync if @opt=''||'' goto help -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == -- if the job is running, do not execute it again if convert(bit,dbo.fn__config(''script_sync'',0))=0 begin -- lock the job launch -- sp__config ''%'' exec sp__config ''script_sync'',1 exec sp__job ''SCRIPT_SYNC'',@sp=''sp__script_sync'',@opt=''run|quiet'' end goto ret sync: -- wiat 5 seconds in case that a second run occur print ''synchronizing...'' -- update log_ddl with (readpast) set udt=getdate() -- exec sp__sync ''log_ddl'',@opt=''>'' waitfor delay ''00:00:05'' exec sp__config ''script_sync'',0 goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope [write here a short desc] Parameters [param] [desc] Examples [exam ple] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_sync' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_sync: -- ========================================================== sp__script_synonym select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_synonym',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121003 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_synonym') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_synonym') with nowait goto skip_sp__script_synonym end if @ver>121003 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_synonym') with nowait goto skip_sp__script_synonym end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_synonym') with nowait if exists( select top 1 null from sys.objects where name='sp__script_synonym' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_synonym] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:follow,synonym,object,table,view v:121003\s.zaglio: follow synonym and return real object or script */ CREATE proc sp__script_synonym @synonym nvarchar(max) = null out, @obj sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common @i int,-- @n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @db sysname,@sql nvarchar(4000), @crlf nvarchar(2), @end_declare bit -- =========================================================== initialization == select @db=isnull(parsename(@obj,3),db_name()), -- @opt1=charindex(''|opt|'',@opt), @synonym=null, @crlf=crlf, @end_declare=1 from fn__sym() -- ======================================================== second params chk == if isnull(@obj,'''')='''' -- @opt=''||'' goto help -- ===================================================================== body == -- follow synonym select @i=1 while not object_id(@obj,N''SN'') is null and @i<4 begin -- exec sp__printf ''-- db=%s, obj=%s'',@db,@obj select @sql='' select @obj=base_object_name from [''+@db+''].sys.synonyms where name=parsename(@obj,1) '' exec sp_executesql @sql,N''@obj sysname out'',@obj out select @db=isnull(parsename(@obj,3),db_name()) select @i=@i+1 end if charindex(''|path|'',@opt)>0 select @synonym=@obj else begin create table #src(lno int identity primary key,line nvarchar(4000)) if @db!=db_name() insert #src select ''use [''+@db+'']'' exec sp__script @obj select @synonym=isnull(@synonym+@crlf,'''')+line from #src order by lno drop table #src end -- script -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. if @dbg=1 exec sp__printsql @synonym goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''write here msg'' goto err err_me2: select @e_msg=''write this %s'',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope follow synonym and return real object or script Parameters @synonym output the real object path or script @obj real object or synonym @opt options path force return of path of object instead of source Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_synonym' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_synonym: -- ============================================================ sp__script_table select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_table',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121010.1700 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_table') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_table') with nowait goto skip_sp__script_table end if @ver>121010.1700 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_table') with nowait goto skip_sp__script_table end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_table') with nowait if exists( select top 1 null from sys.objects where name='sp__script_table' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_table] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility,script v:121010.1700\s.zaglio: added sql92,nopkx options and sql92 output v:121005\s.zaglio: done previous v:121004\s.zaglio: a bug near order of idx with includes v:120919.1300\s.zaglio: a bug near idx with single fld and some includes v:120731.1300\s.zaglio: ix->pk v:120727\s.zaglio: adding #src_def v:120305\s.zaglio: used fn__script_idx v:111028\s.zaglio: moved scripting of triggers in sp__script v:110624\s.zaglio: bug near pkey name and blank lines v:110510\s.zaglio: near help v:110324\s.zaglio: added n/varxxxx(max) and include v:100919\s.zaglio: added advice about fkeys v:100905\s.zaglio: added go before trigger v:100509\s.zaglio: added more noidx,notrg,noidn options v:100404\s.zaglio: a bug near "non custer..." & collate in fn__sql_def.. & quote & idx sep r:100328\s.zaglio: called alone or from sp__script 3.0 t: create table test(id int identity(10,10), i int, r real, f float constraint test_chk check (f<10.4), s sysname,v varchar(12), nv nvarchar(12), c char(10) default ''c10'', nc nchar(10), nn bit not null default 0, num numeric(18,1), dec decimal(18,1), dt datetime constraint test_dt_def default (getdate()), cf as 2*1) create index [ix_test] on [test]([f], [s] desc ) on [primary] create index [ix_test1] on [test]([f] desc ) on [primary] create unique index [ix_test_uk] on [test]([s]) on [primary] go create trigger tr_test_del on test for delete as print ''test'' go create trigger tr_test_ins on test for insert as print ''test'' go exec sp__script_table ''test'' drop table test t:sp__script_table ''cfg'',@opt=''sql92'',@dbg=2 t:sp__script_table ''log_ddl'',@opt=''sql92'',@dbg=2 */ CREATE proc [dbo].[sp__script_table] @obj sysname=null, @opt sysname=null, @dbg int=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @obj is null goto help declare @id int, @db sysname,@sch sysname,@sch_id int, @obj_ex sysname,@obj_in sysname,@q nvarchar(2), @sql nvarchar(4000),@indent sysname, @blank nvarchar(1),@pos int, @i int,@n int,@idx sysname,@pk bit,@uq bit,@cl bit, @def bit, @src_pos int,@src_id int, @src_seed int,@src_incr int, @sql92 bit,@sqlite bit,@nofg bit,@nodbo bit, @noclt bit,@noidx bit,@noidn bit,@nocmt bit,@nopkx bit, @end_declare bit declare @src table(lno int identity primary key,line nvarchar(4000)) select @indent='' '', @opt=dbo.fn__str_quote(coalesce(@opt,''''),''||''), @sqlite=charindex(''|sqlite|'',@opt), @sql92=charindex(''|sql92|'',@opt), @nofg=charindex(''|nofg|'',@opt), @nodbo=charindex(''|nodbo|'',@opt), @noclt=charindex(''|noclt|'',@opt), @noidx=charindex(''|noidx|'',@opt), @noidn=charindex(''|noidn|'',@opt), @nocmt=charindex(''|nocmt|'',@opt), @nopkx=charindex(''|nopkx|'',@opt), @q=case when charindex(''|quote|'',@opt)>0 then ''[]'' else ''[]'' end, @def=isnull(object_id(''tempdb..#src_def''),0), @src_id=isnull(object_id(''tempdb..#src''),0), @src_seed=ident_seed(''#src''), @src_incr=ident_incr(''#src''), @blank='''' if @src_id!=0 select @src_pos=isnull(max(lno),@src_seed) from #src select @db =parsename(@obj,3), @sch=parsename(@obj,2), @obj=parsename(@obj,1) if @db is null select @db=db_name() select @sch=[name],@sch_id=id from dbo.fn__schema_of(@obj) select @obj_ex=quotename(@db)+''.''+coalesce(quotename(@sch),'''')+''.''+quotename(@obj) select @id=object_id(@obj_ex) if @id is null goto err_nof /* sections: 1. usefull select to collect info into common and confortable tables 2. apply options correction (not performant but simple) 3. create scripts from tables */ -- ========================================================================= -- -- =================================================================== tables == select identity(int,1,1) as row_id,0 as lrow_id,* into #table from fn__script_tbl(@id) order by name update #table set lrow_id=(select max(row_id) from #table) -- ================================================================== columns == select identity(int,1,1) as row_id,0 as lrow_id,* into #columns from fn__script_col(@id) order by tablename,tableowner,columnid update #columns set lrow_id=(select max(row_id) from #columns) -- ================================================================== indexes == -- declare @id int select @id=object_id(''???'') select identity(int,1,1) as row_id,0 as lrow_id,* into #indexes -- drop table #indexes from fn__script_idx(@id) order by index_id,index_column_id -- differences last row id on each group of included and not included flds update idxs set lrow_id=lid from #indexes idxs join ( select indexname,is_included_column,max(row_id) lid from #indexes --where is_included_column=1 group by indexname,is_included_column ) ix on idxs.indexname=ix.indexname and idxs.is_included_column=ix.is_included_column -- select row_id,lrow_id,indexname,columnname,is_included_column,* from #indexes -- ========================================================================= -- -- compose source -- remove undesired options if @sqlite=1 begin select @sql92=1 update #columns set typename=''integer'' where typename in (''int'',''bigint'',''tinyint'') update #columns set typename=''blob'' where typename in (''uniqueidentifier'') -- update #columns set typename=''text'' -- where typename typename in (''text'',''ntext'') end if @sql92=1 select @nofg=1,@nodbo=1,@noclt=1,@nopkx=1 if @nofg=1 begin update #table set [owner]=null update #indexes set parentowner=null end if @nodbo=1 begin update #table set [filegroup]=null update #indexes set [filegroup]=null end if @noclt=1 update #columns set collation=null if @noidx=1 truncate table #indexes if @noidn=1 update #columns set [identity]=null if @sql92=1 begin if exists(select top 1 null from #columns c where c.iscomputed=1) goto err_cpt if exists( select top 1 null from #indexes where is_included_column=1 ) exec sp__printf ''-- included columns are not considered'' end -- sql92 limits -- sp__script ''continent'',@opt=''sql92'' -- ============================================================= script table == -- head insert @src select top 1 ''create table ''+coalesce(dbo.fn__str_quote(t.[owner],@q)+''.'','''') +dbo.fn__str_quote(t.[name],@q) +'' ('' -- select t.*,i.[primary] as haspk from #table t -- =========================================================== script columns == insert @src select top 100 percent -- exec sp__script_table ''test'',@opt=''nofg|noclt'' @indent+dbo.fn__sql_def_col( -- sp__usage ''fn__sql_def_col'' c.tablename,null, dbo.fn__str_quote(c.columnname,@q),null,c.typename, c.[length],c.[precision],c.scale, c.allownulls,c.dridefaultname,c.dridefaultcode,c.[identity], c.iscomputed,c.computedtext,null/*chkname*/, null/*chkcode*/,c.collation,null,null) +case when row_id!=lrow_id then '','' else '''' end as line -- select c.*,i.[primary] as haspk from #columns c -- select * from #columns order by columnid -- pk inside table if @nopkx=1 begin select @pos=@src_pos+max(lno)*@src_incr from @src select distinct @idx=indexname,@pk=[primary],@uq=[unique],@cl=[clustered] from #indexes where [primary]=1 if @def=1 insert #src_def(xtype,cod,idx,flags) select ''PK'',@idx,@pos, @uq*flags.e+@cl*flags.f from flags insert @src select top 1 @indent+'',constraint ''+dbo.fn__str_quote(indexname,@q)+'' primary key '' +case when @sql92=0 then case [clustered] when 1 then ''clustered '' else ''nonclustered '' end else '''' end +''('' from #indexes where indexname=@idx -- index columns insert @src select @indent+@indent +dbo.fn__str_quote(columnname,@q)+case descending when 1 then '' DESC '' else '' '' end +case when row_id!=lrow_id then '','' else '''' end from #indexes where indexname=@idx and is_included_column=0 order by row_id insert @src select top 1 @indent+'')''+coalesce('' on ''+dbo.fn__str_quote([filegroup],@q),'''') from #indexes where indexname=@idx end -- pk inside table -- foot insert @src select '')''+coalesce('' on ''+dbo.fn__str_quote([filegroup],@q),'''') from #table -- ============================================================= script index == -- add indexes declare @idxs table (id int identity,indexname sysname,pk bit,uq bit,cl bit) insert @idxs select distinct indexname,[primary],[unique],[clustered] from #indexes order by [primary] desc,[indexname] select @i=min(id),@n=max(id) from @idxs while (@i<=@n) begin select @idx=indexname,@pk=pk,@uq=uq,@cl=cl from @idxs where id=@i if @pk=1 and @nopkx=1 goto iterate -- blank line insert @src select @blank select @pos=@src_pos+max(lno)*@src_incr from @src if @def=1 insert #src_def(xtype,cod,idx,flags) select case @pk when 1 then ''PK'' else ''IX'' end ,@idx,@pos, @uq*flags.e+@cl*flags.f from flags -- CREATE [UNIQUE] NONCLUSTERED INDEX [ix_test] ON [dbo].[test] ([f] ASC,[s] DESC) ON [PRIMARY] -- ALTER TABLE [dbo].[test] ADD PRIMARY KEY CLUSTERED ([id] ASC) ON [PRIMARY] -- head if @pk=1 insert @src select top 1 ''alter table ''+coalesce(dbo.fn__str_quote(parentowner,@q)+''.'','''') +dbo.fn__str_quote(parentname,@q) +'' add constraint ''+dbo.fn__str_quote(indexname,@q)+'' primary key '' +case when @sql92=0 then case [clustered] when 1 then ''clustered '' else ''nonclustered '' end else '''' end +''('' from #indexes where indexname=@idx order by row_id else insert @src select top 1 ''create '' +case [unique] when 1 then ''unique '' else '''' end +case when @sql92=0 then case [clustered] when 1 then ''clustered '' else ''nonclustered '' end else '''' end +''index '' +dbo.fn__str_quote(indexname,@q) +'' on '' +coalesce(dbo.fn__str_quote(parentowner,@q)+''.'','''') +dbo.fn__str_quote(parentname,@q) +''('' from #indexes where indexname=@idx order by row_id -- body -- select * from #indexes order by indexname -- exec sp__script_table ''test'' -- index columns insert @src select dbo.fn__str_quote(columnname,@q)+case descending when 1 then '' DESC '' else '' '' end +case when row_id!=lrow_id then '','' else '''' end from #indexes where indexname=@idx and is_included_column=0 order by row_id -- order by columnname -- wrong -- foot -- includes if @sql92=0 and exists( select top 1 null from #indexes where indexname=@idx and is_included_column=1 ) begin insert @src select '') include ('' insert @src select dbo.fn__str_quote(columnname,@q)+case descending when 1 then '' DESC '' else '' '' end +case when row_id!=lrow_id then '','' else '''' end from #indexes where indexname=@idx and is_included_column=1 order by row_id end -- includes insert @src select top 1 '')''+coalesce('' on ''+dbo.fn__str_quote([filegroup],@q),'''') from #indexes where indexname=@idx iterate: select @i=@i+1 end -- loop indx if @nocmt=0 begin if @def=1 begin select @pos=@src_pos+max(lno)*@src_incr from @src insert #src_def(xtype,cod,idx,flags) select ''--'',@obj,@pos,0 end insert @src select @blank insert @src select ''/******************************************************************'' insert @src select '' *** remember that fkeys are script aside with sp__script_fkeys ***'' insert @src select '' ******************************************************************/'' end -- nocmt -- output if @src_id!=0 insert #src(line) select line from @src order by lno else select line from @src order by lno goto ret -- =================================================================== errors == err_nof: exec @ret=sp__err ''object %s not found'', @proc,@p1=@obj_ex goto ret err_cpt: exec @ret=sp__err ''sql92 not support computed columns'', @proc,@p1=@obj_ex goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Options for tables to script: default all dependencies (keys,constraint,indexs,triggers,etc.) nofg no filegroup noclt no collate noidx no indexes notrg no triggers noidn no identity nocmt no comment nodbo no owner nopkx script pk into table and not out as an index sql92 no owner,filegroup,collate,comment '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__script_table' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_table: -- ========================================================= sp__script_template select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_template',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=151108 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_template') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_template') with nowait goto skip_sp__script_template end if @ver>151108 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_template') with nowait goto skip_sp__script_template end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_template') with nowait if exists( select top 1 null from sys.objects where name='sp__script_template' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_template] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:151108\s.zaglio:added collate database_default v:130728.1000\s.zaglio:use sp__script_template_compile v:130724\s.zaglio:doubled performance v:130713,130709\s.zaglio:added (duty) #tpl_cpl;better help and sp__Script_template_test v:130707,130519\s.zaglio:moved init of #tpl here;better info on missing tpl lines v:130430,130301\s.zaglio:a bug when #tpl is empty;a bug near insert #tpl_sec v:121229\s.zaglio:added %dt% and %uid% in unix notation v:120918\s.zaglio:removed exclusion tag from sub substitution and nomixed v:120914\s.zaglio:opt mix is now default and #tpl mix with itself''s secs v:120913\s.zaglio:split of #tpl_sec.line with crlf and a small bug v:120912,120725.1212\s.zaglio:better help;added @spring v:120627,120126\s.zaglio:a bug near mix (ex temp_db.#tpl_sec);#tpl_sec optional v:111230.1509\s.zaglio:probable stable version r:111228,111227\s.zaglio:debugging r:111223,111222\s.zaglio:auto tokens;new concept that reduce caller code v:111221,111220\s.zaglio:done tab management;about @tab as in&out v:111216\s.zaglio:@to searched after @from v:111115\s.zaglio:added "out" opt and removed exlusion of middle section v:111102\s.zaglio:added option v:110824\s.zaglio:better errors and src now is #tpl and #src become output v:110823,110822\s.zaglio:done;added @from,@to,@tab and removed @splitter v:110707,110706\s.zaglio:@bug near #var;added @excludes v:110701.1825,110601\s.zaglio:a bug near replace of ";added tokens v:110630\s.zaglio:help define templates and generate code t:sp__script_template_test */ CREATE proc sp__script_template @section nvarchar(max) = null, @as nvarchar(256) = null, @opt nvarchar(256) = null, @tab int = null out, @tokens nvarchar(4000)= null, @v1 sql_variant = null, @v2 sql_variant = null, @v3 sql_variant = null, @v4 sql_variant = null, @excludes nvarchar(4000)= null, @dbg int = null as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @dbg=2 create table #tpl (lno int identity,line nvarchar(4000)) -- ========================================================= param formal chk == declare @nomix bit,@isection sysname,@crlf nvarchar(2),@lcrlf int,@itab int, @tpl_oid int,@tpl_cpl_oid int select @nomix=charindex(''|nomix|'',@opt), @crlf=crlf, @lcrlf=len(@crlf), @itab=isnull(@tab,0), @tab=isnull(@tab,0), @tpl_oid=object_id(''tempdb..#tpl''), @tpl_cpl_oid=object_id(''tempdb..#tpl_cpl'') from fn__sym() if @tpl_oid is null -- or (object_id(''tempdb..#tpl_sec'') is null and @nomix=0) goto help select @isection=left(@section,128) -- ============================================================== declaration == declare @tpl binary(20), -- hash of template @sep nvarchar(32), @i int,@n int,@dtype int,@null nvarchar, @x1 int,@y1 int,@x2 int,@y2 int,@line nvarchar(4000), @replace_double_quotes bit,@print bit,@out_out bit, @scissors nvarchar(32), @tkn nvarchar(32), -- token @oline nvarchar(4000), -- original line @bos sysname, -- begin of section @lo_lno int,@hi_lno int, -- low and high line number @noimacro bit, @td nvarchar(4), -- tokens delimiter @d datetime, @exclusion sysname, -- pattern for fine comment line @tmp nvarchar(4000), @spring varchar(10), -- space extensor to justify text @start varchar(16), -- pattern of section start @end_deflare bit declare @tkns table ( id int identity(1,1) primary key, -- lno int, -- x1 int, -- x2 int, tkn nvarchar(4000), [val] nvarchar(4000) ) declare @exclusions table ( lno int, pos int, -- left position to exclude tag exclude bit -- 1=is included into exclude tokens ) declare @out table(lno int identity primary key,line nvarchar(4000)) -- =========================================================== initialization == select @as=isnull(@as,''''), -- @isection), @d=getdate(), @sep =''|'', @td=''%'', @dtype=126, @null='''', @replace_double_quotes=charindex(''|replace"|'',@opt), @out_out=charindex(''|out|'',@opt), @print=charindex(''|print|'',@opt), @noimacro=charindex(''|noimacro|'',@opt), @scissors=''-%8<%-'', @tkn=''%[%]%[a-z0-9_]%[%]%'', @exclusion=''%--[|]%[|]'', @start=''[%<]%[>%]:'', @spring=''/*@*/'' -- 120918\s.zaglio: nomixed automatically if... if @as!='''' select @nomix=1 -- ================================================= split and store sections == if @section like ''%[''+@crlf+'']%'' begin select @tpl=hashbytes(''md5'',left(@section,4000)) -- if already compiled if exists(select top 1 null from #tpl_cpl where tpl=@tpl) goto ret select @hi_lno=isnull(max(lno)+1,0) from #tpl insert #tpl(line) select line -- sp__Script_template from dbo.fn__ntext_to_lines(@section,0) exec sp__script_template_compile @tpl,@start,@scissors goto ret end -- compile teplate -- backward compatiblity if @tpl_cpl_oid is null begin create table #tpl_cpl(tpl binary(20),section sysname,y1 int,y2 int) -- print hashbytes(''md5'',''compiled'') select @tpl=0xCB5185196AD3147D58C13C22B2A32292 exec sp__script_template_compile @tpl,@start,@scissors end select @bos=@isection+'':'',@lo_lno=min(lno),@hi_lno=max(lno) from #tpl if @dbg=1 select ''#tpl_cpl'' tbl,section,y1,y2,line from #tpl_cpl join #tpl t on t.lno between y1 and y2 order by lno if not exists(select top 1 null from #tpl) goto err_tpl -- check for sections with null lines if not object_id(''tempdb..#tpl_sec'') is null if exists( select top 1 null from #tpl_sec where line is null and (@isection is null or section=@isection) ) begin if @isection is null select top 3 @isection=isnull(@isection+'','','''')+section from #tpl_sec where line is null goto err_sec end -- collect line number to exclude insert @exclusions(lno,pos,exclude) select lno, case when patindex(@exclusion,rtrim(t.line))>2 then len(rtrim(substring(t.line,1,patindex(@exclusion,rtrim(t.line))-1))) else len(t.line) end as pos, case when patindex(@exclusion,rtrim(t.line))>2 and dbo.fn__str_between( substring(t.line,patindex(@exclusion,rtrim(t.line))+2,128) ,''|'',''|'' ,default ) in ( select token from dbo.fn__str_table(@excludes,@sep) where token!='''' ) then 1 else 0 end as exclude from #tpl t -- select * from #tpl t join @exclusions e on t.lno=e.lno if @isection is null -- after last scissor select top 1 @y1=lno+1 from #tpl where line like @scissors and lno!=@hi_lno -- skip last scissor on last line order by lno desc else -- begin of section select top 1 @y1=lno+1 from #tpl where ltrim(rtrim(line)) = @bos -- 120913\s.zaglio: removed like order by lno if @y1 is null and not @isection is null goto err_snf select @y1=isnull(@y1,@lo_lno) -- end of section (scissors or eof or [ssep]%[ssep] if not @isection is null select top 1 @y2=lno-1 from #tpl where 1=1 and lno>=@y1 and line like @scissors order by lno -- last section end is last line if @y2 is null select @y2=@hi_lno -- ======================================================== second params chk == -- ===================================================================== body == -- extract section lines and mix with info from #tpl_sec or print missing data -- ################################## -- ## -- ## mix -- ## if #tpl_sec contain the section use it, otherwise -- ## replace with original section from #tpl or give error or unk. section -- ## -- ############################################################################# if object_id(''tempdb..#tpl_sec'') is null insert @out(line) select left(t.line,excl.pos) as line from #tpl t left join @exclusions excl on t.lno=excl.lno where 1=1 and t.lno between @y1 and @y2 and not t.line collate database_default like @scissors and excl.exclude=0 order by t.lno else insert @out(line) select case when s.section is null then case when tts.section is null then left(t.line,excl_t.pos) else left(replace(left(t.line,excl_t.pos) collate database_default, tts.section collate database_default, tt.line collate database_default), excl_tt.pos) end else replace(left(t.line,excl_t.pos) collate database_default, s.section collate database_default, s.line collate database_default) end as line from #tpl t left join @exclusions excl_t on t.lno=excl_t.lno left join ( select s.lno*1000+pos lno,s.section,token as line from #tpl_sec s cross apply dbo.fn__str_table_fast(s.line,@crlf) -- where charindex(s.section,t.line)>0 not possible ) s -- #tpl_sec s on charindex(s.section,t.line)>0 left join #tpl_cpl tts on charindex(tts.section,t.line)>0 left join #tpl tt on tt.lno between tts.y1 and tts.y2 left join @exclusions excl_tt on tt.lno=excl_tt.lno where 1=1 and t.lno between @y1 and @y2 and not t.line like @scissors collate database_default and isnull(excl_t.exclude,0)=0 and isnull(excl_tt.exclude,0)=0 order by t.lno,s.lno if @@rowcount=0 goto err_mix insert @tkns(tkn,val) select token, convert(nvarchar(4000), case pos when 1 then @v1 when 2 then @v2 when 3 then @v3 when 4 then @v4 end ) from fn__str_table(@tokens,@sep) if not object_id(''tempdb..#vars'') is null insert @tkns(tkn,val) select v.id, case when sql_variant_property(v.[value],''BaseType'')=''datetime'' then convert(nvarchar(48),v.[value],@dtype) else convert(nvarchar(4000),coalesce(v.[value],@null)) end from #vars v left join @tkns t on v.[id]=t.tkn collate database_default where t.tkn is null -- add local macro if @noimacro=0 insert @tkns(tkn,val) select m.id,m.value from ( select ''%db%'' id,db_name() value union select ''%now%'',convert(nvarchar(48),getdate(),126) union select ''%dt%'',substring(convert(nvarchar(48),getdate(),126),3,14) union select ''%uid%'',system_user+''@''+host_name() ) m left join @tkns t on m.id=t.tkn where t.tkn is null -- introduce here the reading of last indent, if @tab=0 if @tab=0 select top 1 @tab=patindex(''%[^ ]%'',line)-1 -- is a len from @out order by lno desc if @dbg=1 begin select @section as [@section],@as as [@as], @x1 as [@x1],@y1 as [@y1],@x2 as [@x2],@y2 as [@y2], @tab as [@tab],@itab as [@itab] select ''tpl'' tpl,* from #tpl select ''@out'' [out],@isection as sec,* from @out order by lno select ''@tkns'' tkns,* from @tkns select ''#tpl_sec'' sec,* from #tpl_sec select ''@ex'' ex,* from @exclusions end -- dbg declare cs cursor local forward_only for select lno,/*space(@itab)+*/line from @out order by lno /* TODO: convert tokens in inside sections and/or allow that tokens with CRLF will be correctly expandend to allow a correct compare between composed #src and its compiled version */ -- replace tokens & " open cs while 1=1 begin fetch next from cs into @i,@line if @@fetch_status!=0 break if @line is null goto err_nll select @oline=@line select @line=replace(@line,tkn,convert(nvarchar(4000),val)) from @tkns t where charindex(t.tkn,@line)>0 -- count " if @replace_double_quotes=1 begin select @n=0,@i=charindex(''"'',@line,1) while @i>0 select @n=@n+1,@i=charindex(''"'',@line,@i+1) if @n>0 and @n%2=0 select @line=replace(@line,''"'','''''''') end if @line is null goto err_nlr if charindex(@spring,@line)>0 and (80-len(@line)+len(@spring))<=80 select @line=replace( @line, @spring, replicate('' '',80-len(@line)+len(@spring)) ) if @print=1 begin select @tmp=replace(@line,''%'',''%%'') raiserror(@tmp,10,1) with nowait end else update @out set line=@line where current of cs end -- while of cursor close cs deallocate cs if not @isection is null and @nomix=1 insert #tpl_sec(section,line) select @as,line from @out order by lno else begin if @print=0 -- already printed above begin if object_id(''tempdb..#src'') is null or @out_out=1 begin if object_id(''tempdb..#out'') is null select line from @out order by lno else insert #out(line) select line from @out order by lno end -- out to #out else insert #src(line) select line from @out order by lno end -- out to #src end -- out goto ret -- =================================================================== errors == err_mix: exec @ret=sp__err ''fusion (y1:%d,y2:%d)'', @proc,@p1=@y1,@p2=@y2 goto ret err_tpl: exec @ret=sp__err ''empty #tpl'', @proc,@p1=@isection goto ret err_cpl: exec @ret=sp__err ''undeclared #tpl_cpl'', @proc goto ret err_snf: exec @ret=sp__err ''section "%s" not found in #tpl'', @proc,@p1=@isection goto ret err_nlr: exec @ret=sp__err ''null line result in (%s)'', @proc,@p1=@oline goto ret err_nll: exec @ret=sp__err ''null input line (sec:%s)'', @proc,@p1=@isection goto ret err_sec: exec @ret=sp__err ''null line in #tpl_sec for (sec:%s)'', @proc,@p1=@isection goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope help programmer to generate code from template; generally script a section of #tpl in #tpl_sec and finally MIX the specified or last section into console or #src if present. Todo - check for duplicates on init Notes since version 130713, #tpl and #tpl_cpl are duty and inner section of #tpl are not auto expanded (sorry) so you need to pre-expand into #tpl_sec create table #tpl(lno int identity primary key,line nvarchar(4000)) create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) create table #tpl_cpl(tpl binary(20),section sysname,y1 int,y2 int) Parameters #tpl the source template #tpl_cpl is the compiled version of #tpl and allows inner calls as for example between sp__script_group and sp__script #tpl_sec (optional)the template section replacers if omitted, output directly to #src or #out #src (optional) where store the compiled result #out (optional) where store the compiled result if #src is not given @section - templates to init #tpl - script @section of #tpl into #tpl_sec with @section as name (@section identify lines between %section%: and next --8<--8<-- scissor) @tokens are replaced with @v1,@v2,... If null, insert into #src the last section (tipical MAIN at end of code), mixing content from #tpl_sec and replacing words as %tpl_sec.section% with tpl_sec.line (multiple lines are allowed). @as alternative @section name to use when section is scripted into #tpl_sec (this do not do any mix into #src/#out) @opt options, see below @tokens (optional) tokens, separated by | to replace with @v1..4 if omitted, collects couples of %...% (see also #vars) @v1..4 values for tokens @tab out the number of spaces before the splitter or the left spaces of last row of section; if valued, shift the section @excludes tokens (sep. by |) of lines to exclude (line that end with "--|token|" #vars (optional) macro replace (see sp__str_replace) (@tokens overwrite #vars) (macro %db%,%uid%,%dt%,%now% are pre-defined) create table #vars (id nvarchar(16),value sql_variant) @dbg 2 inner create #tpl to test insert Notes 1. if not all sections are covered by #tpl_sec, a list of sections is printed 2. if all sections are covered, the sp merge #tpl and sec into #src or #out or print 3. the indent of ##section## is applied to lines of #tpl_sec 4. There are predefined macros: %db% current db %now% current datetime in current format (126) 5. scissors are skipped (any line like "-%8<%-") -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- 6. /*@*/ justify to right at col 80, the rest of text Options replace" replace " with double '''' noimacro disable autodefinition of inner macros (%db%,%now%,...) print print lines instead insert into #src or #out or #tpl_sec out force output to #out instead of #src Examples -- given this template... exec sp__script_template '''' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %header%: %detail% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %details%: line 1 line 2 -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- '''' -- ... or call the sp @as to out to #tpl_sec to be remixed exec sp__script_template ''''%details%'''',''''%detail%'''' exec sp__script_template ''''%header%'''' see sp__script_template_test, sp__script_group, sp__script_data '' if not object_id(''tempdb..#tpl'') is null and object_id(''tempdb..#tpl_sec'') is null begin exec sp__select_astext '' select line as sections from #tpl where rtrim(line) like ''''%:'''' '' end select @ret=-1 -- ===================================================================== exit == ret: if @dbg>2 exec sp__elapsed @d,@proc return @ret end -- proc sp__script_template' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_template: -- ================================================= sp__script_template_compile select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_template_compile',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130728 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_template_compile') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_template_compile') with nowait goto skip_sp__script_template_compile end if @ver>130728 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_template_compile') with nowait goto skip_sp__script_template_compile end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_template_compile') with nowait if exists( select top 1 null from sys.objects where name='sp__script_template_compile' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_template_compile] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130728\s.zaglio: compile #tpl into #tpl_clp */ create proc sp__script_template_compile @tpl binary(20) = null, @start varchar(16), @scissors nvarchar(32), @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @bos sysname, -- begin of section @lo_lno int,@hi_lno int -- low and high line number -- =========================================================== initialization == -- ======================================================== second params chk == if @tpl is null goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- compile #tpl into #tpl_cpl while 1=1 begin -- search for session begin select top 1 @lo_lno=lno+1,@bos=ltrim(rtrim(line)) from #tpl where ltrim(rtrim(line)) like @start and lno>@hi_lno order by lno if @@rowcount=0 break -- search for session end select top 1 @hi_lno=lno-1 from #tpl where lno>=@lo_lno and (ltrim(rtrim(line)) like @start or ltrim(rtrim(line)) like @scissors) order by lno if @@rowcount=0 select @hi_lno=max(lno) from #tpl select @bos=ltrim(rtrim(left(@bos,charindex('':'',@bos)-1))) insert #tpl_cpl select @tpl,@bos,@lo_lno,@hi_lno end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope compile #tpl into #tpl_clp Parameters [param] [desc] #tpl template source #tpl_clp table with compiled data @opt options (not used) @dbg not used '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_template_compile' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_template_compile: -- ==================================================== sp__script_template_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_template_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130802 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_template_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_template_test') with nowait goto skip_sp__script_template_test end if @ver>130802 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_template_test') with nowait goto skip_sp__script_template_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_template_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_template_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_template_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130802,130709\s.zaglio: test sp__script_template */ CREATE proc sp__script_template_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @chk binary(16),@ochk binary(16), @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @ochk=0x978bf8a6061e18864a27b2c7594f901b, @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- if @run=0 goto help -- =============================================================== #tbls init == create table #src(lno int identity primary key,line nvarchar(4000)) create table #tpl(lno int identity primary key,line nvarchar(4000)) create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) insert #tpl(line) select line from dbo.fn__ntext_to_lines('' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %header%: %detail% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %details%: line %n% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- '',0) -- ===================================================================== body == exec sp__script_template ''%details%'',''%detail%'',@tokens=''%n%'',@v1=1 exec sp__script_template ''%details%'',''%detail%'',@tokens=''%n%'',@v1=2 exec sp__script_template ''%header%'' -- sp__script_template_test exec sp__md5 @chk out exec sp__prints''template source'' exec sp__print_table ''#tpl'' exec sp__prints''template rendered'' exec sp__print_table ''#src'' exec sp__prints''results'' exec sp__printf ''template rendering original:%d'',@ochk exec sp__printf ''template rendering checksum:%d'',@chk -- sp__script_template_test if @chk!=@ochk raiserror(''test failed'',16,1) else exec sp__printf ''test passed'' -- ================================================================== dispose == dispose: drop table #tpl drop table #tpl_sec drop table #src goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test sp__script_template functionalities TODO: * simple test to console * mix a template that contain other template section to #src the section must contain another section (recursion test) * mix template and sections into #out * test tokens and #tpl_sec sections with CRLF Parameters [param] [desc] @opt options @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_template_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_template_test: -- ======================================================== sp__script_templates select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_templates',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130901.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_templates') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_templates') with nowait goto skip_sp__script_templates end if @ver>130901.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_templates') with nowait goto skip_sp__script_templates end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_templates') with nowait if exists( select top 1 null from sys.objects where name='sp__script_templates' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_templates] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130901.1000\s.zaglio:added begin/end params to grp setup v:130802.1804,130730,130725,130724\s.zaglio:collection of scripts */ CREATE proc sp__script_templates @opt sysname = null, @dbg int=0 as begin try set nocount on declare @proc sysname, @ret int select @ret=0 if @opt is null or @opt='''' goto help select @opt=dbo.fn__str_quote(@opt,''|'') -- =================================================================== script == if charindex(''|script|'',@opt)>0 exec @ret=sp__script_template '' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %declarations%: declare @ver decimal(10,4),@aut sysname,@db sysname, @emsg nvarchar(2048),@esev int,@ests int select @db=db_name() -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %obj_ver_chk%: select @ver=null,@aut=null exec sp_executesql N'''' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) '''',N''''@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out'''', @obj=''''%obj%'''',@typ=''''rv'''',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=%ver% begin if @aut!=''''%aut%'''' raiserror(''''local "%s.%s" with same version but different author'''', 16,1,@db,''''%obj%'''') with nowait raiserror(''''skipped "%s.%s" because local is the same'''', 10,1,@db,''''%obj%'''') with nowait goto skip_%obj% end if @ver>%ver% begin raiserror(''''skipped "%s.%s" because local is more recent'''', 10,1,@db,''''%obj%'''') with nowait goto skip_%obj% end end raiserror(''''re-creating "%s.%s"'''',10,1,@db,''''%obj%'''') with nowait %drop% begin try -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %skip_obj%: end try begin catch if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_%obj%: '' -- ==================================================================== group == if charindex(''|group|'',@opt)>0 exec sp__script_template '' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %scr_header%: /******************************************************* ** generated in the:%dt% by %uid% from %db% ** latest objs to %latests_objs% *******************************************************/ set nocount on declare @db sysname,@svr sysname, @emsg nvarchar(2048),@esev int,@ests int select @db=db_name(), @svr=@@servername if @svr=''''%svr%'''' and @db=''''%db_util%'''' --|utility| begin --|utility| raiserror(''''Cannot execute from db where originated.'''', --|utility| 11,1) with nowait --|utility| goto end_of_script --|utility| end --|utility| --|utility| -- check local our target application name --|other| if %config%(%app_name%)=''''%app_name%'''' goto end_of_script --|other| --|other| -- check db version if (select cmptlevel from master..sysdatabases where [name]=@db )<90 begin raiserror(''''DB compatibility level must be at least 90 (MSSql2k5)'''', 10,1) with nowait raiserror(''''Please run "exec sp_dbcmptlevel ''''''''%s'''''''', 90"'''', 10,1,@db) with nowait raiserror('''''''',11,1) with nowait goto end_of_script end if not object_id(''''sp__script_store'''') is null --|other| exec sp__script_store @opt=''''moff'''' --|other| -- for versioning declare @aut sysname, -- store author @ver decimal(14,4), -- used to store new obj version @msg nvarchar(128), -- generic message string @repeat int -- number of repeat of script -- if error of unknow obj, script is -- repeated bacause dependencies if object_id(''''tempdb..#script_results'''') is null create table #script_results( id int identity, dt datetime default(getdate()) not null, who sysname default system_user+''''@''''+isnull(host_name(),''''???''''), grp sysname not null, rep int null, number int null, message nvarchar(2048) not null, severity int not null, state int null, line int null, [procedure] sysname null ) if object_id(''''tempdb..#script_catch'''') is null exec('''' %script_catch_implementation% '''') select @repeat=1 begin_of_script: -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %scr_footer%: dispose: /* to manage dependencies we run eventually the script 2 or 3 times */ if exists( select top 1 null from #script_results where number in (208,207) -- invalid object, invalid column name and rep=@repeat -- a difference between x32 and x64 of mssql 2k5/8 and not message like ''''%''''''''cpu_ticks_in_ms''''''''%'''' ) begin select @repeat=@repeat+1 select @msg=replicate(''''#'''',80)+'''' REPEAT ''''+cast(@repeat as char) raiserror(@msg,10,1) if @repeat<3 goto begin_of_script else begin select db_name() db,* from #script_results raiserror(''''script repeats failure'''',16,1) end end exec %grp_setup% @opt=''''run|end'''' --|setup| -- select * from #script_results -- drop table #script_results exec sp__context_info @opt=''''mdef'''' --|other| end_of_script: -- finished:%dt% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %script_catch_definition%: create proc #script_catch @grp sysname,@repeat int as begin insert #script_results(dt,grp,rep,number,message,severity,state,line,[procedure]) select getdate(),@grp,@repeat, error_number(),isnull(error_message(),''''n/s''''), error_severity(),error_state(), error_line(),error_procedure() end -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %disable_tracer%: -- ########################## -- ## -- ## disable trace db; -- ## hope nobody work on important things while upgrade -- ## -- ######################################################## if not object_id(''''sp__script_trace_db'''') is null exec sp__script_trace_db ''''uninstall'''' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %enable_tracer%: -- ########################## -- ## -- ## re-install/upgrade script tracer -- ## upgrade LOG_DDL if necessary -- ## -- ######################################################## exec sp__script_trace_db ''''install'''' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %obj_core_chk%: select @ver=dbo.fn__script_sign(''''%obj%'''',1) if not @ver is null and @ver=%ver% begin raiserror(''''skipped "%s.%s" because is the same'''', 10,1,@db,''''%obj%'''') with nowait goto skip_%obj% end raiserror(''''re-creating "%s.%s"'''',10,1,@db,''''%obj%'''') with nowait %drop% begin try -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %skip_obj%: exec %grp_setup% @opt=''''run|begin'''' --|setup| end try begin catch exec #script_catch ''''%grp%'''',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_%obj%: '' if charindex(''|move|'',@opt)>0 exec sp__script_template '' -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %header%: /* --|dbg| declare --|dbg| @trgs nvarchar(4000),@crlf nvarchar(2),@n int,@m int, --|dbg| @proc sysname,@err int,@ret int,@d datetime, --|dbg| @ms_key int,@ms_ins int,@ms_del int, @ms_commit int,@ms_alt int,--|dbg| @log_id int,@top int --|dbg| select @crlf=crlf from fn__sym() --|dbg| */ --|dbg| declare @nm int --============================================================================= --== do some test to ensure that condition is not wrong --============================================================================= select @d=getdate() begin try select @n=count(*), @m=sum(case when %where% then 1 else 0 end) from %main% (nolock) if @n=@m begin raiserror("wrong condition try move all data",16,1) goto ret end select @trgs=null --|trgs| select --|trgs| @trgs=isnull(@trgs+@crlf,"") --|trgs| +"alter table %dst% enable trigger " --|trgs| +quotename(name) --|trgs| from %dst_db%.sys.triggers --|trgs| where parent_id=object_id("%dst%") --|trgs| and is_disabled=0 --|trgs| --|trgs| select @idxs=null --|idxs| select --|idxs| @idxs=isnull(@idxs+@crlf,"") --|idxs| +"alter index "+quotename(name) --|idxs| +" on %dst% disable" --|idxs| from %dst_db%.sys.indexes --|idxs| where object_id=object_id("%dst%") --|idxs| and is_disabled=0 --|idxs| and is_unique=0 --|idxs| and [type]!=1 --|idxs| --|idxs| select --|idxs| @trgs=isnull(@trgs+@crlf,"") --|idxs| +"alter index "+quotename(name) --|idxs| +" on %dst% rebuild" --|idxs| from %dst_db%.sys.indexes --|idxs| where object_id=object_id("%dst%") --|idxs| and is_disabled=0 --|idxs| and is_unique=0 --|idxs| and [type]!=1 --|idxs| --|idxs| select --|trgs| @trgs=isnull(@trgs+@crlf,"") --|trgs| +"alter table %src% enable trigger " --|trgs| +quotename(name) --|trgs| from sys.triggers --|trgs| where parent_id=object_id("%src%") --|trgs| and is_disabled=0 --|trgs| --|trgs| -- for delete --|trgs| alter table %src% disable trigger all --|trgs| -- for insert --|trgs| alter table %dst% disable trigger all --|trgs| -- disable dst indexes --|idxs| exec(@idxs) --|idxs| --|idxs| if @dbg=1 exec sp__printf "%s",@idxs --|idxs| --|idxs| select @ms_alt=datediff(ms,@d,getdate()),@d=getdate() -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %begin%: begin tran --------------------------------------------------- begin tran ---- -- select keys to move -- TODO: collect keys for each table to avoid inverse order of deletetion select %top% %pkey% into %keys% from %main% where %where% %orderby% select @nm=@@rowcount if @nm=0 begin exec sp__printf "-- no rows to move for main table %src%" goto skip_move end select @ms_key=datediff(ms,@d,getdate()),@d=getdate() -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %end%: commit ------------------------------------------------------ commit tran ---- select @ms_commit=datediff(ms,@d,getdate()),@d=getdate() %log_commit% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %body_group%: -- ########################## -- ## -- ## %src% -- ## -- ######################################################## insert %dst%( %dst_flds% ) select %tbl_flds% from %main% %main_alias% join %keys% tmp on %on_pkeys% join %src% %alias% --|main| on %join_on% --|main| select @ms_ins=datediff(ms,@d,getdate()),@d=getdate() -- delete from live --|move| delete %alias% --|move| from %main% %main_alias% --|move| join %keys% tmp --|move| on %on_pkeys% --|move| join %src% %alias% --|main|move| on %join_on% --|main|move| select @ms_del=datediff(ms,@d,getdate()),@d=getdate() %log_times% ------------------------------------------------------------------------------- -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %body_single_table%: -- ########################## -- ## -- ## %src% -- ## -- ######################################################## -- select keys to move -- TODO: collect keys for each table to avoid inverse order of deletetion select %top% %pkey% into %keys% from %main% where %where% %orderby% select @nm=@@rowcount if @nm=0 begin exec sp__printf "-- no rows to move for %src%" goto skip_%lbl% end select @ms_key=datediff(ms,@d,getdate()),@d=getdate() begin tran --------------------------------------------------- begin tran ---- insert %dst%( %dst_flds% ) select %tbl_flds% from %src% %alias% join %keys% tmp on %on_pkeys% select @ms_ins=datediff(ms,@d,getdate()),@d=getdate() -- delete from live --|move| delete %alias% from %src% %alias% join %keys% tmp on %on_pkeys% select @ms_del=datediff(ms,@d,getdate()),@d=getdate() commit ------------------------------------------------------ commit tran ---- select @ms_commit=datediff(ms,@d,getdate()),@d=getdate() %log_times% skip_%lbl%: -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %footer%: -- restore triggers --|trgs| exec(@trgs) --|trgs| if @dbg=1 exec sp__printf "%s",@trgs --|trgs| skip_move: if @@trancount>0 rollback end try ---------------------------------------------------------- end try ---- -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %catch%: begin catch select @err=@@error exec @ret=sp__err @cod=@proc,@opt="ex|warn" if @@trancount>0 rollback end catch -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %log_times_section%: insert %log%(dt,tbl,n,ms_key,ms_alt,ms_ins,ms_del,ms_commit) --|nfo| select @dt_log, --|nfo| ''''%src%'''',@nm,@ms_key,@ms_alt,@ms_ins,@ms_del,@ms_commit --|nfo| -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %log_commit_section%: insert %log%(dt,tbl,n,ms_key,ms_alt,ms_ins,ms_del,ms_commit) --|nfo| select @dt_log,''''*'''',0,0,0,0,0,@ms_commit --|nfo| -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- '' -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: select @proc=object_name(@@procid) exec sp__usage @proc,'' Scope common templates for sp__script and sp__script_group Parameters [param] [desc] @opt options script templates for sp__script group templates for sp__script_group move templates for sp__script_move @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_templates' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_templates: -- =========================================================== sp__script_tohtml select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_tohtml',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110621 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_tohtml') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_tohtml') with nowait goto skip_sp__script_tohtml end if @ver>110621 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_tohtml') with nowait goto skip_sp__script_tohtml end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_tohtml') with nowait if exists( select top 1 null from sys.objects where name='sp__script_tohtml' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_tohtml] begin try exec dbo.sp_executesql @statement = N'/* Keep this due MS compatibility l:see LICENSE file g:utility v:110621\s.zaglio: changed syntaxhl. for compatibility with ffox4 v:110614\s.zaglio: adapted to new script group v:100612\s.zaglio: added margins r:100405\s.zaglio: todo: omit headers is exists; manage a mix v:100404\s.zaglio: htmlize the code in #src t:sp__script_tohtml ''sp__script_tohtml'' */ CREATE proc [dbo].[sp__script_tohtml] @obj sysname=null, @dbg smallint=0 -- enable print of debug info as begin set nocount on if @dbg>=@@nestlevel exec sp__printf ''level of debugging:%d'',@@nestlevel declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 declare @crlf nvarchar(2),@txt nvarchar(4000) select @crlf=crlf from fn__sym() if @obj is null and object_id(''tempdb..#src'') is null goto help if object_id(''tempdb..#src'') is null begin create table #src(lno int identity,line nvarchar(4000)) exec sp__script @obj end create table #tmp (lno int identity(10,10),line nvarchar(4000)) select @txt=''
''
insert #tmp select token from dbo.fn__str_table(@txt,@crlf)
insert #tmp select line from #src order by lno
insert #tmp select ''
'' --insert #tmp select ''
'' insert #tmp select '''' truncate table #src insert #src select line from #tmp order by lno drop table #tmp if not @obj is null select line from #src order by lno goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope encapsulate #src code into html Parameters #src source code @obj direct name of obj '' select @ret=-1 ret: return @ret end -- sp__Script_tohtml' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_tohtml: -- ========================================================= sp__script_trace_db select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_trace_db',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131201.0900 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_trace_db') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_trace_db') with nowait goto skip_sp__script_trace_db end if @ver>131201.0900 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_trace_db') with nowait goto skip_sp__script_trace_db end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_trace_db') with nowait if exists( select top 1 null from sys.objects where name='sp__script_trace_db' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_trace_db] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,script v:131201.0900\s.zaglio: adapted to change of tids.svr->tids.srv v:131125\s.zaglio: moved manage of log_ddl into sp__utility_setup v:131002\s.zaglio: moved code from trigger db to sp__script_store v:120924\s.zaglio: added upgrade of log_ddl from 1477379425 to 45011731 v:120907\s.zaglio: removed skip of objs %__% from tr v:120824\s.zaglio: bug when zero condition near drop of fn__script_trace v:120517\s.zaglio: bug about create of fn__script_trace v:120516\s.zaglio: adapted to new fn__script_sysobjs v:120512.1522\s.zaglio: managed new DML and CTRL events v:120213\s.zaglio: adapted to new fn__script_events v:120208\s.zaglio: removed identity in log_ddl and done fn__script_trace r:120207\s.zaglio: working r:120206\s.zaglio: modified fn__script_trace and log_ddl d:120103\s.zaglio: sp__util_ddl v:111205\s.zaglio: bug given by change of sp__script_compile beahviour v:110830\s.zaglio: adapted to new fn__buildin v:110629\s.zaglio: now trigger exclude %__% v:110628.1644\s.zaglio: managed not presence of sp__script_store v:110624\s.zaglio: added remove d:110623\s.zaglio: sp__script_trace v:110510\s.zaglio: added trace view filter by id and obj name v:110415.1712\s.zaglio: added test of cmptlvl and fn__strace generation v:110315\s.zaglio: reduced table size and introduced some checks and exclus. v:110313\s.zaglio: done vertioning of all db objects r:110312\s.zaglio: 1st draft t:sp__script_trace_db ''install'' -- sp__Script_history t:sp__script_trace_db ''uninstall'' t:sp__script_trace_db ''remove'' t:select * from log_ddl order by dt desc */ CREATE proc sp__script_trace_db @opt nvarchar(4000)=null, @dbg bit=null as begin set nocount on /* select t.name,* from sys.trigger_events e join sys.triggers t on t.object_id=e.object_id select * from sys.sql_modules where object_id=142675606 select * from sys.events select * from sys.trigger_events e */ declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0,@dbg=isnull(@dbg,0), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') declare @sql nvarchar(max),@tr_name sysname,@events nvarchar(max), @tab2 sysname,@crlf nvarchar(2),@srv_id int,@db_id int, @tmp nvarchar(4000),@fdb smallint, @tsrv tinyint,@tdb tinyint,@thost tinyint, @tapp tinyint,@tsql tinyint,@tobj tinyint, @tev tinyint, @cond nvarchar(32),@db sysname,@srv sysname, @srv_hash int,@db_hash int,@udt datetime, @counter_id int, @cmd_install bit,@cmd_uninstall bit, @cmd_remove bit,@upgrade bit, @ftype smallint select @counter_id =-2147483648, @upgrade =0, @udt= getutcdate(), @srv= dbo.fn__servername(null), @db= db_name(), @srv_hash=dbo.fn__crc32(@srv), @db_hash=dbo.fn__crc32(@db), @cmd_remove=charindex(''|remove|'',@opt), @cmd_install=charindex(''|install|'',@opt), @cmd_uninstall=charindex(''|uninstall|'',@opt), @srv_id=@counter_id+1, @db_id= @counter_id+2, @tr_name=replace(@proc,''sp_'',''tr_''), @crlf=crlf,@tab2='' '' from fn__sym() -- prevent errors due change to tids,flags if (@cmd_install=@cmd_uninstall and @cmd_remove=0) goto help if @dbg=0 and exists(select null from sys.triggers t where t.name=@tr_name) begin exec(''drop trigger [''+@tr_name+''] on database'') if @@error!=0 goto err_rem else exec sp__printf ''DB trace trigger %s removed'',@tr_name end if @cmd_uninstall=1 goto ret if @cmd_remove=1 begin drop table LOG_DDL goto ret end exec sp_executesql N'' select @tsrv= tids.srv, @tdb= tids.db, @thost= tids.host, @tapp= tids.app, @tsql= tids.code, @tobj= tids.obj, @tev= tids.ev, @fdb= flags.db, @ftype= flags.[type] from tids,flags '',N'' @tsrv tinyint out,@tdb tinyint out,@thost tinyint out, @tapp tinyint out,@tsql tinyint out,@tobj tinyint out, @tev tinyint out,@fdb smallint out,@ftype smallint out '', @tsrv=@tsrv out,@tdb=@tdb out,@thost=@thost out, @tapp=@tapp out,@tsql=@tsql out,@tobj=@tobj out, @tev=@tev out,@fdb=@fdb out,@ftype=@ftype out if @opt is null or (@cmd_install=@cmd_uninstall and @cmd_remove=0) goto help create table #blob(id int identity,blob ntext) create table #src(lno int identity,line nvarchar(4000)) create table #vars (id nvarchar(16),value sql_variant) insert #vars select ''%buildin%'',dbo.fn__script_buildin(getdate(),1,@proc,''autogeneration'') insert #vars select ''%proc%'', @proc insert #vars select ''%tr_name%'',@tr_name insert #vars select ''%tsrv%'', @tsrv insert #vars select ''%tdb%'', @tdb insert #vars select ''%thost%'', @thost insert #vars select ''%tapp%'', @tapp insert #vars select ''%tsql%'', @tsql insert #vars select ''%tobj%'', @tobj -- ================================================================= db trace == db_trace: if (select cmptlevel from master..sysdatabases where [name]=@db )<90 goto err_cml -- ============================================================ upgrade table == exec sp__utility_setup @opt=''run|log_ddl'' -- =============================================== re-create reading function == -- drop function fn__script_trace if object_id(''fn__script_trace'') is null or exists( select null from dbo.fn__script_info(''fn__script_trace'',''v'',0) where val1!=''131006.1100'' ) begin if not object_id(''fn__script_trace'') is null exec(''drop function fn__script_trace'') exec sp__printf ''-- creating fn__script_trace'' exec(''/* leave this l:see LICENSE file v:131006.1100\sp__script_trace: generated automatically t:select * from fn__script_trace(null,null,null) order by dt desc */ create function fn__script_trace( @obj sysname, @p2 bit,@p3 bit ) returns table as return select l.id, l.srv srv_id, o.rid db_id, o.skey as obj, case l.tid when tids.code then case when l.flags & flg.ver=flg.ver then ''''ver'''' else ''''rel'''' end -- tsql else cast(l.flags as nvarchar) end as flags, u.skey as usr, substring(l.txt,1,4000) as code, l.ev, l.rel, l.dt from tids,flags flg,log_ddl l with (readpast) join log_ddl o with (readpast) on o.tid=(select obj from tids) and o.id=l.rid join log_ddl u with (readpast) on u.tid=(select usr from tids) and u.id=l.pid where l.tid=tids.code and (@obj is null or l.rid=(select id from log_ddl where tid=(select obj from tids) and [key]=dbo.fn__crc32(@obj) and skey=@obj ) ) -- end fn__script_trace '' ) end -- ============================================================= trigger code == insert #blob(blob) select ''/* leave this g:utility,trace v:%buildin% d:110628\s.zaglio:tr__script_trace */'' insert #blob(blob) select ''create trigger %tr_name% on database for '' -- =================================================================== events == select identity(int,1,1) id,@tab2+cod ev into #events -- select * from fn__script_sysobjs(@tev) ev join dbo.fn__str_table(@opt,''|'') op on op.token!='''' and ev.cod like ''%''+op.token+''%'' where ev.flags&@fdb=@fdb and ev.flags&@ftype=0 if @@rowcount=0 insert #events(ev) select @tab2+cod ev -- select * from fn__script_sysobjs(@tev) ev where ev.flags&@fdb=@fdb and ev.flags&@ftype=0 update #events set ev=ev+'','' where id!=(select max(id) from #events) insert #blob(blob) select ev from #events if @@rowcount=0 goto err_ev insert #blob(blob) select ''as begin set nocount on declare @et sysname,@obj sysname,@app nvarchar(256), @sql nvarchar(max) select @app=left(app_name(),256) if left(@app,8)=''''SQLAgent'''' return select @et=EVENTDATA().value(''''(/EVENT_INSTANCE/EventType)[1]'''',''''nvarchar(256)''''), @obj=EVENTDATA().value(''''(/EVENT_INSTANCE/ObjectName)[1]'''',''''nvarchar(256)''''), @sql=EVENTDATA().value(''''(/EVENT_INSTANCE/TSQLCommand)[1]'''',''''nvarchar(max)'''') if object_id(''''sp__Script_store'''') is null goto err_prc exec sp__script_store @et,@obj,@sql goto ret -- =================================================================== errors == err_prc: print ''''%tr_name%: WARNING sp__script_store not found to store ''''+@obj ret: end -- trigger %tr_name% '' -- split blob into lines exec sp__write_ntext_to_lines @crlf=0 -- replace macros exec sp__str_replace ''#src'',''#vars'' /* type date-time spid name name name name name name type command */ if @dbg=1 exec sp__printsql ''#src'' else begin exec @ret=sp__script_compile @opt=''noalter'' if @ret!=0 exec sp__printsql ''#src'' else exec sp__printf ''DB trace trigger %s installed'',@tr_name end goto ret -- =================================================================== errors == err_cml: exec @ret=sp__err ''compatibility level to low; Use: declare @db sysname select @db=db_name() EXEC sp_dbcmptlevel @db, 90'',@proc goto ret err_rem: exec @ret=sp__err ''trigget not removed'',@proc goto ret err_ev: exec @ret=sp__err ''no events to attach'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope install/upgrade/uninstall DDL trigger. (Data Definition Language) Notes Create the fn__script_trace. The DB trigger call the "sp__script_store" and this run a job that call the "sp__script_sync". See also sp__script_history. Parameters @opt options install install db trigger uninstall uninstall db trigger event|... limit Examples sp__script_trace_db "install" -- List of events '' exec sp__select_astext '' select ev.cod as [*event name*], case when ev.flags & flags.srv = flags.srv then ''''srv'''' when ev.flags & flags.db = flags.db then ''''db'''' end as [*type*] from flags,fn__script_sysobjs((select ev from tids)) ev where ev.flags&flags.db=flags.db and ev.flags&flags.[type]=0 order by 1 '',@header=1 help_trace_view: if not object_id(''fn__script_trace'') is null and not object_id(''log_ddl'') is null begin select @sql='' select * from fn__script_trace(%obj%,default,default) where %cond% order by dt desc,id desc '' if @db is null select @db=''default'',@cond=''1=1'' else if isnumeric(@db)=1 select @cond=''id=''+@db,@db=''default'' else select @db=dbo.fn__str_quote(@db,''''''''),@cond=''1=1'' exec sp__str_replace @sql out,''%obj%|%cond%'',@db,@cond exec(@sql) end else exec sp__printf ''\n*** fn__script_trace absent; will be installed from this sp ***'' ret: return @ret end -- sp__script_trace_db' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_trace_db: -- ========================================================= sp__script_transfer select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_transfer',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121010 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_transfer') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_transfer') with nowait goto skip_sp__script_transfer end if @ver>121010 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_transfer') with nowait goto skip_sp__script_transfer end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_transfer') with nowait if exists( select top 1 null from sys.objects where name='sp__script_transfer' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_transfer] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:move, script, remote, server r:121010\s.zaglio: short comment t: sp__script_transfer ''test'', ''continent|country|state|province|city|place|civic| palces|civics'',@opt=''sqlite'' ,@dbg=2 */ CREATE proc sp__script_transfer @dst sysname = null, @objs nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common @i int,@n int, -- index, counter @sql nvarchar(max), -- dynamic sql -- options @nodata bit, @obj sysname,@typ sysname, @drop sysname, @crlf nvarchar(4), @end_declare bit create table #src(lno int identity, line nvarchar(4000)) -- =========================================================== initialization == select @nodata=charindex(''|nodata|'',@opt),@opt=replace(@opt,''|nodata|'',''|''), @crlf=crlf, @end_declare=1 from fn__sym() -- ======================================================== second params chk == if @opt=''||'' goto help -- ===================================================================== body == declare cs cursor local for select o.token,so.typ,so.[drop] from fn__str_params(@objs,''|'',default) o join fn__sysobjects(default,default,default) so on o.token=so.obj -- select top 1 * from sys.objects open cs while 1=1 begin fetch next from cs into @obj,@typ,@drop if @@fetch_status!=0 break exec sp__prints @obj truncate table #src exec sp__Script @obj,@opt=@opt select @sql=''drop ''+@drop+'' if exists ''+@obj+'';'' select @sql=isnull(@sql+@crlf,'''')+line from #src order by lno select @sql=''exec(''+@crlf+ ''''''''+replace(@sql,'''''''','''''''''''')+''''''''+@crlf+ '') at ''+quotename(@dst) if @dbg>0 exec sp__printsql @sql if @dbg<2 exec(@sql) if @nodata=0 and @typ=''U'' begin select @sql=dbo.fn__sql_trim('' insert openquery(''+@dst+'', ''''select * from ''+@obj+'''''' ) select * from ''+@obj) if @dbg>0 exec sp__printsql @sql if @dbg<2 exec(@sql) end -- @nodata end -- cursor cs close cs deallocate cs -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''write here msg'' goto err err_me2: select @e_msg=''write this %s'',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope script objects one by one and execute on remote @dst server; useful for ODBC or non MSSQL engines Parameters @dst linked server @objs list of objects separated by | @opt options nodata do not transfer data for tables ... pass the option to sp__script @dbg 1 print sql and execute 2 print sql but not execute Examples [example] -- list of remove servers -- '' exec sp__select_astext '' select name,data_source,catalog,collation_name from sys.servers '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__script_transfer' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_transfer: -- ====================================================== sp__script_update_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_update_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140204 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_update_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_update_test') with nowait goto skip_sp__script_update_test end if @ver>140204 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_update_test') with nowait goto skip_sp__script_update_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_update_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_update_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_update_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:140204\s.zaglio: little refactor and added not practical test v:140203\s.zaglio: added different base code (regular,irregular) v:140130\s.zaglio: added tests for not commented and merge update v:140116\s.zaglio: added tests for ovr option v:131220\s.zaglio: test revision v:131217\s.zaglio: another global revision v:131216\s.zaglio: remake and relaxed tests v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:''sp__script_update_test @dbg=2'' */ CREATE proc sp__script_update_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @id int,@name sysname,@sql nvarchar(4000), @crlf nvarchar(2),@st sysname, @msg nvarchar(2000),@log_id int, @obj_code nvarchar(max), @obj_name sysname, @typ char, @result sysname -- =========================================================== initialization == select @obj_name=''tst_sp__script_update_test_obj'', @crlf=crlf from fn__sym() -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == -- =============================================================== #tbls init == create table #test( id int identity primary key, name sysname, target_code char(1) check (target_code in (''R'',''I'')), sql nvarchar(max), opt sysname, result char(1), status nvarchar(4000) null, log_id int null ) create table #targets( code char, sql nvarchar(max) ) -- =============================================================== test cases == if not object_id(@obj_name) is null exec(''drop proc ''+@obj_name) -- ########################## -- ## -- ## source code -- ## -- ######################################################## insert #targets(code,sql) -- irregular select ''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216\s.zaglio: remake and relaxed tests v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' union -- regular select ''R'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' -- ########################## -- ## -- ## upgrade code -- ## -- ######################################################## select @opt='''',@obj_code=sql from #targets where code=''I'' -- this first case must be first because the object -- will be created from case test 2 insert #test(name,opt,result,target_code,sql) select ''target not exists'',@opt,''N'',''I'',@obj_code ----------------------------------------------------------- insert #test(name,opt,result,target_code,sql) select ''target exists and has no comments'',@opt,''U'',''I'',@obj_code ----------------------------------------------------------- union all select ''daily modification'',@opt,''U'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216.1000\s.zaglio: remake and relaxed tests with small chg v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''fake daily modification'',@opt,''C'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216.1000\s.zaglio: changed whole comment v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''older'',@opt,''O'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check todo:calculate new correction dates on last+x d:131011\s.zaglio:sp_nothing v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test #1#2#3#4#5,@dbg=2 */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''same'',@opt,''S'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216\s.zaglio: remake and relaxed tests v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''newer for small comment correction'',@opt,''U'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216\s.zaglio: remake and relaxed tests. v:131216\s.zaglio: not specified hhmm. v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''conflict and missin hour'',@opt+''|sd'',''C'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check todo:calculate new correction dates on last+x r:131216\s.zaglio: remake and relaxed tests. v:131024\s.zaglio: added case with missed hour v:131024\s.zaglio: added case 5. v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test #1#2#3#4#5,@dbg=2 */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''compile error'',@opt,''E'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131217\s.zaglio: update but with compile error v:131216\s.zaglio: remake and relaxed tests v:131216\s.zaglio: not specified hhmm v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print hello '' ----------------------------------------------------------- union all select ''conflict with two missing comment'',@opt,''C'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131217\s.zaglio: update but with compile error v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''older but OVERWRITE'',''ovr|''+@opt,''U'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check todo:calculate new correction dates on last+x d:131011\s.zaglio:sp_nothing v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test #1#2#3#4#5,@dbg=2 */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''update of merged'',''sd|''+@opt,''U'',''I'','' /* leave this l:see LICENSE file g:utility k:upgrade,conflict,author,different,check v:131216\s.zaglio: remake and relaxed tests v:131216\s.zaglio: not specified hhmm v:131216\a.ziglio: merged code v:131024\s.zaglio: added case 5 v:131021\s.zaglio: final release r:131018\s.zaglio: added SD option test v:131008\s.zaglio: added more case r:131007\s.zaglio: test different cases t:sp__script_update_test */ create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- union all select ''not practical code'',''sd|''+@opt,''E'',''I'','' create proc ''+@obj_name+'' as print ''''hello'''' '' ----------------------------------------------------------- -- this is used by #update_log create table #update_log( id int identity, dt datetime default(getdate()) not null, who sysname default system_user+''@''+isnull(host_name(),''???''), obj sysname, sts char, -- Updated,New,Same,Older,Conflict,Error msg nvarchar(2000) ) -- ===================================================================== body == -- drop existing base object of previour bug of test if not object_id(@obj_name) is null exec(''drop proc ''+@obj_name) declare cs cursor local for select id,name,sql,opt,result,target_code from #test open cs while 1=1 begin fetch next from cs into @id,@name,@sql,@opt,@result,@typ if @@fetch_status!=0 break select @obj_code=sql from #targets where code=@typ if @dbg>1 begin exec sp__prints ''target code'' exec sp__printsql @obj_code end if @dbg>0 begin select @name as [case],@opt as [option],@result as expected exec sp__prints ''case %s(%s):%s'',@id,@typ,@name end -- after test 1, create base the object to modify -- case 2 obj without comments if @id=2 exec(''create proc ''+@obj_name+'' as print ''''hello'''''') if @id>2 exec(@obj_code) select @log_id=max(id)+1 from #update_log select @log_id=isnull(@log_id,1) select @st=cast(@dbg as sysname) select @sql=''exec sp__script_update @opt=''''''+@opt+'''''',@dbg='' +@st+'',@src=N''''''+replace(@sql,'''''''','''''''''''')+'''''''' if @dbg>1 begin exec sp__printsql @sql exec sp__prints ''result'' end begin try exec (@sql) select @msg=null end try begin catch select msg=error_message() end catch -- drop altered object exec(''drop proc ''+@obj_name) update test set log_id=@log_id, status=case when test.result=log.sts then ''ok''+isnull('':''+@msg,'''') else ''ko''+isnull('':''+@msg,'''') end from #test test join #update_log log on log.id=@log_id where test.id=@id end -- cursor cs close cs deallocate cs select @sql=''select ''''#test'''' tbl,log_id,id,name,status from #test'' exec(@sql) select @sql=''select ''''#update_log'''' tbl,* from #update_log'' exec(@sql) if exists(select top 1 null from #test where status like ''ko%'') raiserror(''test failed'',16,1) -- ================================================================== dispose == dispose: drop table #test drop table #update_log goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test different cases for sp__script_update Parameters [param] [desc] @opt (not used) @dbg passed to sp__script_update Examples sp__script_update_test -- list of test cases --- '' exec sp__select_astext ''select id,name from #test order by id'' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_update_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_update_test: -- =============================================== sp__script_utility_setup_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__script_utility_setup_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=140109 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__script_utility_setup_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__script_utility_setup_test') with nowait goto skip_sp__script_utility_setup_test end if @ver>140109 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__script_utility_setup_test') with nowait goto skip_sp__script_utility_setup_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__script_utility_setup_test') with nowait if exists( select top 1 null from sys.objects where name='sp__script_utility_setup_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__script_utility_setup_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:140109\s.zaglio: check t:sp__script_utility_setup_test run */ CREATE proc sp__script_utility_setup_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @run bit -- =========================================================== initialization == select @run=charindex(''|run|'',@opt) -- ======================================================== second params chk == if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == -- test if fn__job work in this system exec @ret=sp__job_test @opt=''setup'' -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test the full functionality of the utility that can fail depending from MSSQL version or OS configuration Parameters [param] [desc] @opt options run tun tests @dbg debug level 1 basic info and do not execute dynamic sql 2 more details (usually internal tables) and execute dsql 3 basic info, execute dsql and show remote info Examples sp__script_utility_setup_test run '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__script_utility_setup_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__script_utility_setup_test: -- =========================================================== sp__select_asform select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__select_asform',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130517 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__select_asform') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__select_asform') with nowait goto skip_sp__select_asform end if @ver>130517 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__select_asform') with nowait goto skip_sp__select_asform end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__select_asform') with nowait if exists( select top 1 null from sys.objects where name='sp__select_asform' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__select_asform] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:130517\s.zaglio: changed inner #temp tables names; added dot opt v:120925\s.zaglio: small bug near @where v:120918\s.zaglio: adding option #vars v:100919\s.zaglio: adde @p1,... but not well tested v:100214\s.zaglio: show 1st record of a table in vertical form t: select id,name,xtype,crdate into #t from sysobjects where xtype=''p'' exec sp__select_asform ''#t'',''name="sp__select_asform"'',@dbg=1 drop table #t */ CREATE proc sp__select_asform @tbl sysname=null, @where nvarchar(4000)=null, @opt sysname=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @tbl is null goto help select @opt=dbo.fn__str_quote(@opt,''|''),@ret=0 declare @vars bit,@select bit,@sql nvarchar(max), @crlf nvarchar(4),@n int, @flds nvarchar(4000), @dot bit select @tbl=parsename(@tbl,1), @vars=charindex(''|#vars|'',@opt), @select=charindex(''|select|'',@opt), @dot=charindex(''|dot|'',@opt), @where=replace(@where,''"'',''''''''), @crlf=crlf, @flds=dbo.fn__flds_of(@tbl,'','',null) from fn__sym() if not @p1 is null select @tbl=replace(@tbl,''{1}'',convert(sysname,@p1,126)), @where=replace(@where,''{1}'',convert(sysname,@p1,126)) if not @p2 is null select @tbl=replace(@tbl,''{2}'',convert(sysname,@p2,126)), @where=replace(@where,''{2}'',convert(sysname,@p2,126)) if not @p3 is null select @tbl=replace(@tbl,''{3}'',convert(sysname,@p3,126)), @where=replace(@where,''{3}'',convert(sysname,@p3,126)) if not @p4 is null select @tbl=replace(@tbl,''{4}'',convert(sysname,@p4,126)), @where=replace(@where,''{4}'',convert(sysname,@p4,126)) select @where=isnull(''where ''+@where,'''') create table #sp__select_asform_fld( id int identity primary key, fld sysname, value sql_variant null, dsc sysname null ) if @vars=1 insert #sp__select_asform_fld(fld) select token as dsc from dbo.fn__str_table(@flds,'','') else insert #sp__select_asform_fld(fld,dsc) select token,coalesce(com.value,'''') as dsc from dbo.fn__str_table(@flds,'','') left join ( select * from dbo.fn__comments(@tbl) where not column_name is null ) com on token=com.column_name -- declare @tbl sysname,@where sysname select @tbl=''sysobjects'',@where='''' select @sql =isnull(@sql+@crlf,'''')+''when ''''''+fld +'''''' then cast(#sp__select_asform_tmp.[''+fld+''] as sql_variant)'' from #sp__select_asform_fld select @sql =''select top 1 * into #sp__select_asform_tmp from [''+@tbl+''] ''+@crlf +@where+@crlf +''update #sp__select_asform_fld set value=''+@crlf +''case fld''+@crlf +@sql+@crlf +''end''+@crlf +''from #sp__select_asform_tmp'' if @dbg=1 exec sp__printsql @sql exec(@sql) if @@error!=0 goto err_cod if @vars>0 begin insert #vars(id,value) select ''%''+f.fld+''%'',f.value from #sp__select_asform_fld f left join #vars v on ''%''+f.fld+''%''=v.id where v.id is null update v set v.value=f.value from #sp__select_asform_fld f join #vars v on ''%''+f.fld+''%''=v.id end else begin if @dot=1 begin select @n=max(len(fld))+2 from #sp__select_asform_fld update #sp__select_asform_fld set fld=fld+replicate(''.'',@n-len(fld)) end if @select>0 select id,fld,value,dsc from #sp__select_asform_fld order by id else exec sp__select_astext ''select fld,value,dsc from #sp__select_asform_fld'', @opt=@opt end drop table #sp__select_asform_fld goto ret -- =================================================================== errors == err_cod: exec @ret=sp__err ''inside code'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope print a vertical table with 1st record of @tbl Parameters @tbl name of table (can be a #temp) @where condition to filter select @p1,... replaces {1},{...} into @tbl and @where @opt options select return results as select instead of text #vars out/update table #vars with results as %fld%,value h passed to sp__select_astext noh passed to sp__select_astext dot fill fld column with dots .... '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__select_asform' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__select_asform: -- =========================================================== sp__select_astext select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__select_astext',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130517.1700 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__select_astext') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__select_astext') with nowait goto skip_sp__select_astext end if @ver>130517.1700 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__select_astext') with nowait goto skip_sp__select_astext end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__select_astext') with nowait if exists( select top 1 null from sys.objects where name='sp__select_astext' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__select_astext] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility d:130521\s.zaglio:sp__select v:130517.1700\s.zaglio: a bug near print into @out and h and noh opts v:130424\s.zaglio: again adapted to be multi collate v:130422\s.zaglio: removed use of fn__str_print v:121025\s.zaglio: better identification of last "from" v:121024\s.zaglio: adapted to be multi collate v:120830.1518\s.zaglio: a bug near hdr when out ot #tbl or select v:120809\s.zaglio: use of fn__sql_normalize v:120801\s.zaglio: bug new into ... porder by v:120724\s.zaglio: added auto enclose of union into () v:120723.1700\s.zaglio: added footer in html out if @header=2 v:120723\s.zaglio: chk of unions and a bug generating html file v:120720.1531\s.zaglio: converted order by 1,2,... into names v:120720.1243\s.zaglio: corrected new and old order by problem r:120719\s.zaglio: added html and done test (wrong order) r:120718\s.zaglio: a remake for mssql2k5> (20% faster) v:120717\s.zaglio: test for -- presence v:120307\s.zaglio: better error management v:120116\s.zaglio: added #src,#out,p4 options v:111130\s.zaglio: when @out=#html or .htm?, now send a real table v:110831\s.zaglio: return error if write to file fail v:110308\s.zaglio: more help v:110219\s.zaglio: added out as select and @sep as varchar32 v:110112\s.zaglio: added right trim v:101201\s.zaglio: added row2,3,4 for very big tables v:100911\s.zaglio: added type distinctions between datetime, reals, etc in convert v:100718\s.zaglio: added @p1,@p2... v:100612\s.zaglio: more debug info v:100522\s.zaglio: a bug when @header=0 and added 1 or 2 headers option v:100404\s.zaglio: adj. help and added
v:100328\s.zaglio: removed doubled from run in exec(...) v:100228\s.zaglio: added @sep,quoted names and order by v:100115\s.zaglio: adjusted header padding and managed 0 rows table v:100107\s.zaglio: @out=null -> normal select v:100105\s.zaglio: normalized sql v:091229\s.zaglio: added help and @header v:091227\s.zaglio: show results of tbl/qry as text table with col''autosize t: exec sp__select_astext '' select top 10 id,name [name/test],crdate,cast(0x1221 as image) im from sysobjects order by [name/test] desc '' ,@dbg=1 ,@opt=''html'' ,@out=''%temp%\sp__select_astext_test.htm'' exec master..xp_cmdshell ''type %temp%\sp__select_astext_test.htm'' exec master..xp_cmdshell ''del %temp%\sp__select_astext_test.htm'' t: create table #src(lno int identity,line nvarchar(4000)) truncate table #src exec sp__select_astext '' select name,id [code],xtype,crdate from sysobjects order by code '' ,@dbg=2 ,@out=''#src'',@opt=''html'' select * from #src exec sp__email @to=''stefano.zaglio@seltris.it'', @body=''#src'', @from=''sp__select_astext_test@seltris.it'' drop table #src drop table #t t: select top 10 * into #t from sysobjects order by crdate desc select * from #t exec sp__select_astext ''select * from #t'' exec sp__select_astext ''select * from #t order by id'',@dbg=1 exec sp__select_astext ''select * from #t order by 2 desc,uid, 1'',@dbg=2 drop table #t t: exec sp__select_astext '' select name,id [code],xtype,crdate from sysobjects order by code '',@out=''select'' */ CREATE proc [dbo].[sp__select_astext] @what nvarchar(max)=null, -- table/view/select @out sysname=null, @header tinyint=null, @sep nvarchar(32)=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @opt sysname=null, @dbg int=0 as begin set nocount on declare @proc sysname, @ret int, @err int, @id int, @i int, -- index @crlf nvarchar(2), @cr nvarchar(1), @lf nvarchar(1), @tab nvarchar(1), @tmp sysname, -- name of ##tmp tables @html bit, -- mark out as html @csep nvarchar(255), -- output column separator @chead nvarchar(255), -- column head separator @cfoot nvarchar(255), -- column footer sep. @sql nvarchar(max), -- dinamyc sql @oby nvarchar(4000), -- keep orderby clause @row nvarchar(max), -- final row select format @hth nvarchar(4000), -- html table header @hdr nvarchar(4000), -- header tmp string @hstyle nvarchar(4000), -- html table header style @q char(1), -- quote char '' @dq char(2), -- double quote char '''' @declare_end bit declare @src table(lno int identity primary key,line nvarchar(4000)) select @proc=object_name(@@procid),@crlf=crlf,@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''), @cr=cr,@lf=lf,@tab=tab,@crlf=crlf from dbo.fn__sym() if @what is null goto help if charindex(''--'',@what)>0 goto err_lce -- normalize sql select @what=dbo.fn__sql_normalize(@what,''sel'') -- replace parameters if right(@what,1)=''='' select @what=@what+convert(sysname,@p1,126),@p1=null if not @p1 is null select @what=replace(@what,''{1}'',convert(sysname,@p1,126)) if not @p2 is null select @what=replace(@what,''{2}'',convert(sysname,@p2,126)) if not @p3 is null select @what=replace(@what,''{3}'',convert(sysname,@p3,126)) if not @p4 is null select @what=replace(@what,''{4}'',convert(sysname,@p4,126)) -- 120718\s.zaglio: aligned to sp__usage if not @p1 is null select @what=replace(@what,''%p1%'',convert(sysname,@p1,126)) if not @p2 is null select @what=replace(@what,''%p2%'',convert(sysname,@p2,126)) if not @p3 is null select @what=replace(@what,''%p3%'',convert(sysname,@p3,126)) if not @p4 is null select @what=replace(@what,''%p4%'',convert(sysname,@p4,126)) if @dbg>0 exec sp__printsql @what create table #html (lno int identity,line nvarchar(4000)) -- for html output create table #cols ( col sysname, -- name typ sysname, -- type pos smallint identity primary key, -- colord spos as cast(pos as varchar(5)), -- pos as string width smallint, -- max col width swidth as cast(width as varchar(5)), -- width as string cst nvarchar(512), -- cast code csep bit -- if column separator ) -- init constants/vars select @q ='''''''', @dq ='''''''''''', @html =case when charindex(''|html|'',@opt)>0 then 1 when right(@out,4)=''.htm'' then 1 when right(@out,5)=''.html'' then 1 else 0 end, @header=isnull(@header, case when charindex(''|h|'',@opt)>0 then 1 when charindex(''|noh|'',@opt)>0 then 0 else 2 end), @csep =case @html when 1 then '''' else isnull(replace(@sep,@q,@dq),'' '') end, @chead =case @html when 1 then '''' else '''' end, @cfoot =case @html when 1 then '''' else '''' end, @hth ='''', @hstyle=''background-color:darkgray;color:white;text-align:center;''+ ''font-size:120%;font-size:120%;font-weight:bold;font-style:italic'' -- hive off sql pieces of code select @i = charindex('' order by '',@what) if @i>0 select @oby=substring(@what,@i+10,4000),@what=left(@what,@i) else select @oby='''' select @i = charindex('' union '',@what) if @i>0 begin if charindex(''('',@what)>@i or charindex('')'',@what,@i)=0 select @what=''select * from (''+@what+'') a'' end select @i = dbo.fn__charindex('' from '',@what,-1) -- @i is used below near INTO if @i=0 goto err_from if charindex(''|#src|'',@opt)>0 select @out=''#src'' if charindex(''|#out|'',@opt)>0 select @out=''#out'' if charindex(''|p4|'', @opt)>0 select @out=convert(nvarchar(512),@p4) -- create tmp table 1 select @tmp=''##tmp''+replace(convert(sysname,newid()),''-'',''''), @sql=left(@what,@i)+'' into ''+@tmp +substring(@what,@i,len(@what)) +case @oby when '''' then '''' else '' order by ''+@oby end exec(@sql) select @err=@@error,@id=@@identity if @err!=0 begin exec sp__printf @sql goto err_sql end if @dbg>0 exec sp__printsql @sql -- get flds info insert #cols(col,typ,csep,width) select c.name,t.name,1,len(c.name) from tempdb..syscolumns c join tempdb..systypes t on c.xusertype=t.xusertype where c.id=object_id(''tempdb..''+@tmp) and t.name!=''image'' update #cols set csep=0 where pos=@@identity -- due the final select a+b+c.. the order by n fail because n can be only 1 -- we split order by fields and replace it with names if @oby!='''' begin declare @obyf table( pos int, fld nvarchar(4000), nfld nvarchar(4000), ord sysname, sep char(1) ) insert @obyf( pos, fld, ord, sep ) select pos, dbo.fn__str_at(ltrim(rtrim(token)),'' '',1), isnull(dbo.fn__str_at(ltrim(rtrim(token)),'' '',2),''''), '','' from dbo.fn__str_table(@oby,'','') order by pos update @obyf set sep='''' where pos=(select max(pos) from @obyf) if @dbg>0 exec sp__printf ''@oby:%s'',@oby update tbl set nfld=(select a.col from #cols a where a.spos=tbl.fld collate database_default) from @obyf tbl where isnumeric(tbl.fld)=1 -- recompound clause select @oby='''' select @oby=@oby+isnull(nfld,fld)+'' ''+ord+sep from @obyf order by pos select @oby='' order by ''+@oby if @dbg>1 select ''@obyf'' tbl,* from @obyf if @dbg>0 exec sp__printf ''@oby:%s'',@oby end -- order by -- set casting (note: can be optimized more) update #cols set cst= ''isnull(''+case when typ in (''text'',''ntext'') then ''substring(''+quotename(col)+'',1,4000)'' when typ like ''%char'' then quotename(col) when typ like ''%date%'' or typ like ''%time%'' then ''convert(nvarchar(4000),''+quotename(col)+'',126)'' else ''cast(''+quotename(col)+'' as nvarchar(4000))'' end+'','''''''')'' -- calculate max width of each column select @sql=null select @sql=isnull(@sql+'','',''declare '')+''@c''+spos+'' smallint'' from #cols select @sql=@sql++@crlf+''select '' select @sql=@sql+'' @c''+spos+''=max(len(''+cst+''))'' +case csep when 1 then '','' else '''' end from #cols select @sql=@sql+''from ''+@tmp+@crlf select @sql=@sql+''update #cols set width='' +''case ''+ +''when @c''+spos+''>width then @c''+spos+'' '' +''else width end '' -- if width of header is greater +''where pos=''+spos+@crlf from #cols if @dbg>0 exec sp__printsql @sql exec(@sql) select @err=@@error if @err!=0 begin exec sp__printf @sql goto err_sql end if @dbg>1 select ''#col'' tbl,* from #cols -- prepare header table for txt out if @html=0 begin select @hdr='''' select @hdr=@hdr+left(col+replicate('' '',width),width) +case csep when 1 then @csep else '''' end from #cols order by pos select @hdr=rtrim(@hdr) -- optimization end -- txt headers -- =================================================================== output == -- compound final select row select @row='''' if @html=1 select @row = @row +cst +case csep when 1 then ''+''''''+@csep+''''''+'' else '''' end from #cols order by pos else select @row = @row +case swidth when ''0'' then '''' else ''cast(''+cst+'' as nchar(''+swidth+''))'' end +case csep when 1 then ''+''''''+@csep+''''''+'' else '''' end from #cols order by pos -- add row header and footer select @row=@q+@chead+''''''+''+@row+''+''''''+@cfoot+@q if @dbg>0 exec sp__printsql @row -- output middle table if dbg if @dbg>1 exec(''select ''+@row+'' from ''+@tmp+@oby) if @dbg>0 exec sp__printf ''-- print'' if @html=0 begin if @out is null begin if @header in (1,2) print @hdr select @sql='' declare @line nvarchar(4000) declare c cursor local for select rtrim(''+@row+'') collate database_default as line from ''+@tmp+@oby+'' open c while (1=1) begin fetch next from c into @line if @@fetch_status!=0 break -- print dbo.fn__str_print(@line) print @line end close c deallocate c '' if @dbg>0 exec sp__printf @sql exec(@sql) select @err=@@error if @err!=0 begin exec sp__printf @sql goto err_sql end if @header=2 print @hdr end -- print else begin if @out=''select'' begin if @header in (1,2) insert @src select @hdr insert @src exec(''select rtrim(''+@row+'') line from ''+@tmp+@oby) if @header in (1,2) insert @src select @hdr select line from @src order by lno end else -- insert to table begin select @sql='''' if @header in (1,2) select @sql=''insert into ''+@out+''(line) '' +''values(''''''+replace(@hdr,'''''''','''''''''''')+'''''')'' +@crlf select @sql = @sql + '';insert into ''+@out+''(line) '' + ''select rtrim(''+@row+'') as line '' + ''from ''+@tmp+@oby if @header in (1,2) select @sql=@crlf+@sql+ +'';insert into ''+@out+''(line) ''+ +''values(''''''+replace(@hdr,'''''''','''''''''''')+'''''')'' exec(@sql) select @err=@@error if @err!=0 begin exec sp__printsql @sql goto err_sql end end end -- @out end -- no html else begin -- is html insert #html select @hth -- insert header select @hdr='''' select @hdr=@hdr+'''' from #cols order by pos select @hdr=''''+@hdr+'''' insert #html select @hdr select @sql =''insert into #html(line) '' +''select ''+@row+'' as line '' +''from ''+@tmp+@oby exec(@sql) select @err=@@error,@id=@@identity if @header=2 update #html set line=replace(line,'''','''') where lno=@id if @err!=0 begin exec sp__printf @sql goto err_sql end insert #html select ''
''+col+''
'' if @out is null begin if @dbg>0 exec sp__printf ''-- out to:text as html'' exec sp__print_table ''#html'' end else begin if @out=''select'' begin if @dbg>0 exec sp__printf ''-- out to:select as html'' exec(''select line from #html order by lno'') end else begin if left(@out,1)=''#'' begin if @dbg>0 exec sp__printf ''-- out to:#table as html'' select @sql =''insert into ''+@out+''(line) '' +''select line '' +''from #html '' +''order by lno'' exec(@sql) select @err=@@error if @err!=0 begin exec sp__printf @sql goto err_sql end end else begin if @dbg>0 exec sp__printf ''-- out to:file as html'' exec @ret=sp__file_write @out,@table=''#html'' -- the below add chars at top of text that are not -- correctly readed -- exec @ret=sp__file_write_stream @out,@opt=''html'' end end end end -- out if @err!=0 goto err dispose: drop table #html exec(''drop table ''+@tmp) goto ret -- =================================================================== errors == err: goto ret err_len: exec @ret=sp__err ''null len'',@proc goto ret err_ofm: exec @ret=sp__err ''out of memory string'',@proc goto ret err_lce: exec @ret=sp__err ''line comment -- illegal'',@proc goto ret err_from: exec @ret=sp__err ''cluase FROM absent'',@proc goto ret err_sql: exec @ret=sp__err ''bad sql code'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Parameters: @what can be a table or a query (use top clause) @out can be a #table or .htm/.html file if "select", return as select @p1... replace "%p1%","%p2%",... in @what befor execute (retro-compatible with {1},{2}...) @header default is 2 and * when txt out: 0 do not print 1 print header as name of columns 2 print footer as name of columns * when htm out: 0 do not add headers 1 add highlighted header as name of columns 2 highlight last row @opt options html return a ...
structure * can be combined with @out * implicit if @out end with .htm... #src set out to this table #out set out to this table p4 (experimental)set @out to @p4 h show only top header noh do not show any header @dbg 1 print inside code 2 show mid table content Notes * order by is applied on result query so in: select fld1 as [a] from tbl order by fld1 must become: select fld1 as myname from tbl order by myname * FROM clause must be present '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- sp__select_astext' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__select_astext: -- =============================================================== sp__server_ip select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__server_ip',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131020 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__server_ip') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__server_ip') with nowait goto skip_sp__server_ip end if @ver>131020 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__server_ip') with nowait goto skip_sp__server_ip end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__server_ip') with nowait if exists( select top 1 null from sys.objects where name='sp__server_ip' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__server_ip] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:131020\s.zaglio: get server ip t: create proc tst_server_ip as declare @ip sysname exec sp__server_ip @ip out print ''-''+@ip go exec tst_server_ip drop proc tst_server_ip */ CREATE proc sp__server_ip(@ip sysname=null out) as begin declare @cmd sysname declare @out table(line sysname null) select @cmd=''@for /f "tokens=5 delims= " %d '' +''in (''''ping %srv% -4 -n 1 ^| find /i "ping %srv%"'''') '' +''do @echo %d'' select @cmd=replace(@cmd,''%srv%'',cast(serverproperty(''machinename'') as sysname)) insert @out exec xp_cmdshell @cmd select top 1 @ip=substring(line,2,len(line)-2) from @out if @@nestlevel=1 and dbo.fn__isconsole()=1 print @ip end -- sp__server_ip' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__server_ip: -- ================================================================ sp__snapshot select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__snapshot',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=111116 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__snapshot') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__snapshot') with nowait goto skip_sp__snapshot end if @ver>111116 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__snapshot') with nowait goto skip_sp__snapshot end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__snapshot') with nowait if exists( select top 1 null from sys.objects where name='sp__snapshot' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__snapshot] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:111116\s.zaglio:removed use of fn__format v:111115\s.zaglio:create quickly a snapshot of a db t:sp__snapshot #,@dbg=1 */ CREATE proc sp__snapshot @db sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @opt is null or @db is null goto help if @db!=''#'' and not exists(select null from master..sysdatabases where [name]=@db) goto err_ndb if @db=''#'' select @db=db_name() -- ============================================================== declaration == declare @sql nvarchar(max), @ndb sysname,@dt nvarchar(32), @psep nvarchar(4),@d datetime create table #src(lno int identity, line nvarchar(4000)) create table #files( fileid int, [name] sysname, [path] nvarchar(512), [file] sysname, [ext] sysname ) -- =========================================================== initialization == select @psep=psep, @d=getdate(), @dt=convert(nvarchar(32),@d,8), @dt=convert(nvarchar(32),@d,12)+''_''+substring(@dt,1,2)+substring(@dt,4,2), @ndb=quotename(@db+''_''+@dt), @db=quotename(@db) -- select * from fn__sym() -- ======================================================== second params chk == -- ===================================================================== body == -- collect files of db select @sql='' insert #files(fileid,[name],[path],[file],ext) select fileid, [name], substring([filename],1,(len([filename])-charindex(psep,reverse([filename])))+1) as [path], substring([filename],(len([filename])-charindex(psep,reverse([filename])))+2,128) as [file], substring([filename],(len([filename])-charindex(''''.'''',reverse([filename])))+2,128) as [ext] from fn__sym(),''+@db+''..sysfiles sf where status & 0x40 = 0; update #files set [file]=substring([file],1,len([file])-len([ext])-1) '' exec (@sql) if @@error!=0 exec sp__printsql @sql if not exists(select top 1 null from #files) goto err_nof insert #src(line) select ''create database ''+@ndb+'' on ('' insert #src(line) select '' name = ''+[name]+'', filename =''+crlf+ '' ''''''+[path]+[file]+''_''+@dt+''.ss'''' ''+crlf from fn__sym(),#files insert #src(line) select '') as snapshot of ''+@db if @dbg>0 exec sp__print_table ''#src'' else exec @ret=sp__script_compile if @@error=0 and @ret=0 exec sp__printf ''-- drop database %s'',@ndb drop table #src drop table #files goto ret -- =================================================================== errors == err_ndb: exec @ret=sp__err ''database "%s" not found'',@proc,@p1=@db goto ret err_nof: exec @ret=sp__err ''database "%s" with no files?'',@proc,@p1=@db goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create quickly a snapshot of a db into the same data directory with same name and extension YYMMDD_HHMMSS Parameters @db name of database (# for current) @dbg debug options 1 print sql instead of execute Examples '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__snapshot' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__snapshot: -- ================================================================ sp__str_join select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_join',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081114 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_join') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_join') with nowait goto skip_sp__str_join end if @ver>081114 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_join') with nowait goto skip_sp__str_join end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_join') with nowait if exists( select top 1 null from sys.objects where name='sp__str_join' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_join] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:081114\S.Zaglio: join strings with a @separator. PArameters must not null t: begin declare @s nvarchar(4000) exec sp__str_join @s out,''|'',''1'',''a'',''2'',''b'',@test=1 exec sp__str_join @s out,''|'',''c'',''1'',''2'',''b'',@test=1 -- test auto resets exec sp__str_join @s out,''|'',@s,''d'',''3'',''4'',''e'',@test=1 -- test keep end */ CREATE proc sp__str_join @sentence nvarchar(4000) out, @sep nvarchar(32), @v1 sql_variant, @v2 sql_Variant=null, @v3 sql_Variant=null, @v4 sql_Variant=null, @v5 sql_Variant=null, @v6 sql_Variant=null, @v7 sql_Variant=null, @v8 sql_Variant=null, @v9 sql_Variant=null, @v10 sql_Variant=null, @v11 sql_Variant=null, @v12 sql_Variant=null, @v13 sql_Variant=null, @v14 sql_Variant=null, @v15 sql_Variant=null, @v16 sql_Variant=null, @test bit=0 as begin declare @n int, @i int declare @v sql_variant set @i=1 set @n=16 while (@i<=@n) begin if @i=1 set @v=@v1 if @i=2 set @v=@v2 if @i=3 set @v=@v3 if @i=4 set @v=@v4 if @i=5 set @v=@v5 if @i=6 set @v=@v6 if @i=7 set @v=@v7 if @i=8 set @v=@v8 if @i=9 set @v=@v9 if @i=10 set @v=@v10 if @i=11 set @v=@v11 if @i=12 set @v=@v12 if @i=13 set @v=@v13 if @i=14 set @v=@v14 if @i=15 set @v=@v15 if @i=16 set @v=@v16 if @v is null break if @i=1 set @sentence='''' if @sentence<>'''' set @sentence=@sentence+@sep set @sentence=@sentence+convert(nvarchar(4000),@v) set @i=@i+1 end -- while if @test=1 print @sentence end -- fn__str_replace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_join: -- =============================================================== sp__str_print select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_print',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100404 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_print') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_print') with nowait goto skip_sp__str_print end if @ver>100404 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_print') with nowait goto skip_sp__str_print end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_print') with nowait if exists( select top 1 null from sys.objects where name='sp__str_print' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_print] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100404\s.zaglio: print tokens tabbed t:sp__str_print ''one,two,longname,first_name,last_name,this is a sentence,test 1234'' ,'','',@indent='' '' ,@out=''#src'' */ create proc sp__str_print @objs nvarchar(4000),@sep nvarchar(32)=''|'', @indent sysname='''', @out sysname=null, @len int=80 as begin set nocount on declare @n int,@ll int,@txt nvarchar(4000),@k int,@crlf nvarchar(2) select @crlf=crlf from dbo.fn__sym() declare @tkns table(pos int,token sysname,sep nvarchar(32)) insert @tkns select pos,token,@sep from dbo.fn__str_table(@objs,@sep) select @len=@len-len(@indent) select @n=max(len(token))+1,@k=max(pos) from @tkns select @txt=null,@ll=((@len/@n*@n)+2) update @tkns set sep='''' where pos=@k select @txt =coalesce(@txt,@indent)+left(token+sep+replicate('' '',@n),@n) +case when pos%(@len/@n)=0 then @crlf+@indent else '' '' end from @tkns order by pos if @out is null print @txt else begin select @txt=''insert ''+@out+'' select ''''''+replace(@txt,'''''''','''''''''''')+'''''''' exec(@txt) end end -- sp__str_print' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_print: -- ============================================================= sp__str_replace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_replace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120416 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_replace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_replace') with nowait goto skip_sp__str_replace end if @ver>120416 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_replace') with nowait goto skip_sp__str_replace end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_replace') with nowait if exists( select top 1 null from sys.objects where name='sp__str_replace' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_replace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120416\s.zaglio: @sentence to nvarchar(max) v:110823\s.zaglio: better help v:110512\s.zaglio: a bug near @tbl v:110415\s.zaglio: a bug on inline multiple tags v:110316\s.zaglio: a remake v:091029\s.zaglio: management of error within len(token)>16 now 32 v:091025\s.zaglio: a little remake using @tables; @tbl is changed to bit and used fixed name #vars v:091022\s.zaglio: expanded limits of 16 tockens if @tbl not null v:091016.2000\s.zaglio: added help v:090918\s.zaglio: restyle v:090610\S.Zaglio: added @sep v:090123\S.Zaglio: added @null parameters for null constant for null values v:090121\S.Zaglio: added imput data from table (##) v:090113\S.Zaglio: added max tokens check v:081219\S.Zaglio: added @inject for special sql replaces v:081214\S.Zaglio: changed again convert to 126 because damn MSSQL v:081212\S.Zaglio: changed convert date from 126 to 120 because MSSQL QA 2k-2k8 don''t accept T v:081130\S.Zaglio: added auto convertion of datetime values to iso8601 v:081016\S.Zaglio: removed @from and added check for multi or single tokens v:081007\S.Zaglio: added @from as costant source for @sentence v:080909\S.Zaglio: if @tokens is null become eq to @sentence and work like a fn__str_join v:080815\S.Zaglio: added spaces trim on tokens to allow well format coding and @v9-@v16 v:080807\S.Zaglio: added @test,@v5-7 and correcteed bug in convertion v:080729\S.Zaglio: multiple replace */ CREATE proc [dbo].[sp__str_replace] @sentence nvarchar(max)=null out, @tokens nvarchar(4000)=null, @v1 sql_variant=null, @v2 sql_variant=null, @v3 sql_variant=null, @v4 sql_variant=null, @v5 sql_variant=null, @v6 sql_variant=null, @v7 sql_variant=null, @v8 sql_variant=null, @v9 sql_variant=null, @v10 sql_variant=null, @v11 sql_variant=null, @v12 sql_variant=null, @v13 sql_variant=null, @v14 sql_variant=null, @v15 sql_variant=null, @v16 sql_variant=null, @test bit=null, @dstyle tinyint=null, @inject bit=null, @tbl bit=null, @null sysname=null, @sep sysname=null, @dbg bit=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @sentence is null goto help select @test =isnull(@test,0), @dstyle =isnull(@dstyle,126), @inject =isnull(@inject,0), @tbl =isnull(@tbl,0), @null =isnull(@null,''''), @sep =isnull(@sep,''|''), @dbg =isnull(@dbg,0) declare @n int,@i int, @v sql_variant,@tl smallint, -- max token name length @vv nvarchar(4000),@t sysname, @single bit, @token nvarchar(4000) -- a id bigger than 16 cause mssql warning about rec size>8096 byes declare @tkns table ( id int identity(1,1) primary key, tkn nvarchar(4000), val sql_variant null ) select @tl=32 if @tokens=''#vars'' insert @tkns(tkn,val) select id,[value] from #vars if @tbl=1 insert @tkns(tkn,val) select id,[value] from #vars v -- 110512\s.zaglio -- join dbo.fn__str_table(@tokens,@sep) t -- on t.token=v.id if @tokens!=''#vars'' and @tbl!=1 begin insert @tkns(tkn) select left(token,@tl) from dbo.fn__str_table(@tokens,@sep) t if exists(select null from @tkns where len(tkn)>@tl) goto err_tln update @tkns set val=@v1 where id=1 update @tkns set val=@v2 where id=2 update @tkns set val=@v3 where id=3 update @tkns set val=@v4 where id=4 update @tkns set val=@v5 where id=5 update @tkns set val=@v6 where id=6 update @tkns set val=@v7 where id=7 update @tkns set val=@v8 where id=8 update @tkns set val=@v9 where id=9 update @tkns set val=@v10 where id=10 update @tkns set val=@v11 where id=11 update @tkns set val=@v12 where id=12 update @tkns set val=@v13 where id=13 update @tkns set val=@v14 where id=14 update @tkns set val=@v15 where id=15 update @tkns set val=@v16 where id=16 end -- if @tokens!=''#vars'' and @tbl!=1 -- convertion to string update @tkns set val=case when SQL_VARIANT_PROPERTY(val,''BaseType'')=''datetime'' then convert(nvarchar(48),val,@dstyle) else convert(nvarchar(4000),coalesce(val,@null)) end if @dbg=1 select * from @tkns if @sentence!=''#src'' update @tkns set @sentence=replace(@sentence,tkn,convert(nvarchar(4000),val)) from @tkns else begin declare cs cursor local forward_only for select lno,line from #src open cs while 1=1 begin fetch next from cs into @i,@vv if @@fetch_status!=0 break select @vv=replace(@vv,tkn,convert(nvarchar(4000),val)) from @tkns t where charindex(t.tkn,@vv)>0 update #src set line=@vv where lno=@i end -- while of cursor close cs deallocate cs end -- #src replace if @test=1 begin if @sentence!=''#src'' print @sentence else exec sp__print_table ''#src'' end goto ret -- =================================================================== errors == err_tln: exec sp__err ''token name greater than %s'',@proc,@p1=@tl goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope replace pieces of sentence Parameters @sentence the source to replace (or #src) #src alternative source (lno int identity,line nvarchar(4000)) @tokens the pieces to replace separated by @sep (or #vars) @v1..@v16 the values relative to tokens #vars alternative tokens (id nvarchar(16),value sql_variant) @test print the result @dstyle date style (default 126) @inject inject the values into '''''''' @tbl if 1, uses content of #vars instead of @v1..v16 @null replace nulls values with this @sep by default "|", is the separator of tokens @dbg debug mode; print some info for developer Examples: declare @r real,@d datetime select @r=10.12345678,@d=getdate() exec sp__str_replace ''''%s;r=%r;d=%d'''', ''''%r|%d|%s'''', @r,@d,''''replaced'''' ,@test=1 exec sp__str_replace ''''this %is% the %n%st %tst%'''', ''''%is%|%n%|%tst%'''', ''''is'''',1 ,''''test'''' ,@test=1 table mode 1: create table #vars (id nvarchar(16),value sql_variant) declare @st sysname insert #vars values(''''%a%'''',''''STEFANO'''') insert #vars values(''''%d%'''',getdate()) set @st=''''my name is %a% and now is %d% local time'''' exec sp__str_replace @st out,''''%a%|%d%'''',@tbl=1,@test=1 drop table #vars table mode 2: create table #src (lno int identity,line nvarchar(4000)) create table #vars (id nvarchar(16),value sql_variant) insert #src(line) select ''''this %is% test'''' insert #src(line) select ''''of the %dt%'''' insert #vars values(''''%is%'''',''''is'''') insert #vars values(''''%dt%'''',getdate()) exec sp__str_replace ''''#src'''',''''#vars'''',@test=1,@dbg=1 drop table #vars drop table #src '' select @ret=-1 ret: return @ret end -- sp__str_replace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_replace: -- ================================================================ sp__str_swap select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_swap',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081212 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_swap') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_swap') with nowait goto skip_sp__str_swap end if @ver>081212 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_swap') with nowait goto skip_sp__str_swap end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_swap') with nowait if exists( select top 1 null from sys.objects where name='sp__str_swap' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_swap] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:081212\S.Zaglio: swap two varaibles t:begin declare @a sysname,@b sysname set @a=''a'' set @b=''b'' exec sp__str_swap @a out,@b out print @a print @b end */ CREATE proc sp__str_swap @a nvarchar(4000) out,@b nvarchar(4000) out as begin declare @t nvarchar(4000) set @t=@a set @a=@b set @b=@t end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_swap: -- =============================================================== sp__str_table select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_table',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100508 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_table') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_table') with nowait goto skip_sp__str_table end if @ver>100508 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_table') with nowait goto skip_sp__str_table end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_table') with nowait if exists( select top 1 null from sys.objects where name='sp__str_table' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_table] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100508\s.zaglio: adde hwhere parameters with @p1,@p2,... v:100113\s.zaglio: added test comment v:091027\s.zaglio: name that start with #,@ are not closed into % and managed (n)text flds v:091018\s.zaglio: verticalize a row of a table into a #vars for str_replace t: create table #vars (id nvarchar(16),value sql_variant) create table #local(id int,name sysname) insert #local select 1,''one'' insert #local select 2,''two'' exec sp__str_table ''#vars'',''#local'',''id=%d'',@p1=2-- ,@dbg=1 declare @sql sysname select @sql=''id:%id%; name:%name%'' exec sp__str_replace @sql out,@tbl=1 print @sql drop table #local drop table #vars */ CREATE proc [dbo].[sp__str_table] @vtbl sysname=null, @htbl sysname=null, @hwhere sysname=null, @excludes sysname=null, @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @dbg bit=0 as begin set nocount on declare @flds nvarchar(4000),@types nvarchar(4000), @declares nvarchar(4000),@select nvarchar(4000), @inserts nvarchar(4000),@crlf nchar(2),@sql nvarchar(4000), @i int,@n int,@fld sysname,@type sysname,@sfld sysname if @vtbl is null or @htbl is null goto help select @crlf=char(13)+char(10), @flds =dbo.fn__flds_of(@htbl,''|'',null), @types=dbo.fn__flds_type_of(@htbl,''|'',null), @select='''',@declares='''',@inserts='''', @i=1,@n=dbo.fn__str_count(@flds,''|'') while (@i<=@n) begin select @fld =dbo.fn__str_at(@flds ,''|'',@i) select @sfld=quotename(@fld) select @type=dbo.fn__str_at(@types,''|'',@i) if @type in (''text'',''ntext'') select @sfld=''convert(nvarchar(4000),''+@sfld+'') '' if @type in (''text'',''ntext'') select @type=''nvarchar(4000)'' if dbo.fn__at(@fld,@excludes,''|'')=0 begin select @declares=@declares+''@''+@fld+'' ''+@type+case when @i<@n then '','' else '''' end+@crlf select @select=@select+''@''+@fld+''=''+@sfld+case when @i<@n then '','' else '''' end select @inserts=@inserts+''insert ''+@vtbl+'' select '''''' +case when left(@fld,1) in (''#'',''@'') then @fld else ''%''+@fld+''%'' end +'''''',@''+@fld+@crlf end select @i=@i+1 end select @sql=''truncate table ''+@vtbl+@crlf +''declare''+@crlf+@declares +''select top 1 ''+@select+'' from ''+@htbl+@crlf +coalesce(''where '' +dbo.fn__printf(@hwhere,@p1,@p2,@p3,@p4,null,null,null,null,null,null) ,'''') +@crlf +@inserts if @dbg=1 exec sp__printf @sql exec(@sql) goto ret help: select @sql=''Verticalize a row of a table into a table to pass to sp__str_replace Sample: create table #vars(id nvarchar(16), value sql_variant) create table #objs(id int,name sysname,age int,b bit, e nvarchar(10), t ntext) insert #objs select 1,''''first'''',10,1,''''v10'''',''''text1'''' insert #objs select 2,''''second'''',20,2,''''v20'''',''''text2'''' exec sp__str_table ''''#vars'''',''''#objs'''',''''id=%d'''',@p1=1 select * from #vars drop table #vars drop table #objs'' exec sp__usage ''sp__str_table'',@sql ret: end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_table: -- ========================================================== sp__str_table_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_table_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130925 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_table_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_table_test') with nowait goto skip_sp__str_table_test end if @ver>130925 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_table_test') with nowait goto skip_sp__str_table_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_table_test') with nowait if exists( select top 1 null from sys.objects where name='sp__str_table_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_table_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:130925\s.zaglio:test for fn__str_table */ CREATE proc sp__str_table_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @test table(tst nvarchar(max),pos int,token nvarchar(4000)) insert @test select ''a|b|cc'',0,''|'' -- main test insert @test select ''a|b|cc'',1,''a'' -- result insert @test select ''a|b|cc'',2,''b'' -- result insert @test select ''a|b|cc'',3,''cc'' -- result insert @test select ''a\n\nc'',0,''\n'' -- main test insert @test select ''a\n\nc'',1,''a'' insert @test select ''a\n\nc'',2,'''' insert @test select ''a\n\nc'',3,''c'' insert @test select ''a b c d'',0,'''' -- main test insert @test select ''a b c d'',1,''a'' insert @test select ''a b c d'',2,''b'' insert @test select ''a b c d'',3,''c'' insert @test select ''a b c d'',4,'''' insert @test select ''a b c d'',5,''d'' -- =========================================================== initialization == -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == select case when tst.token=t.token then ''ok'' else ''ko'' end sts, tst.tst,tst.pos,tst.token tst_token,t.token fn_result into #t from @test tst full outer join ( select t.tst,f.pos,f.token from @test t cross apply fn__str_table(tst,token) f where t.pos=0 ) t on tst.tst=t.tst and tst.pos=t.pos where tst.pos!=0 exec sp__select_astext ''select * from #t order by 1,2,3'' exec sp__printf '''' exec sp__prints ''8<'' exec sp__printf '''' -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test for fn__str_table Parameters [param] [desc] @opt (not used) @dbg (not used) Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__str_table_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_table_test: -- =========================================================== sp__str_unpattern select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__str_unpattern',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120528 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__str_unpattern') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__str_unpattern') with nowait goto skip_sp__str_unpattern end if @ver>120528 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__str_unpattern') with nowait goto skip_sp__str_unpattern end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__str_unpattern') with nowait if exists( select top 1 null from sys.objects where name='sp__str_unpattern' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__str_unpattern] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120528\s.zaglio:wrapper for fn__str_unpattern */ CREATE proc sp__str_unpattern @blob ntext =null, @filter sysname =null, @opt sysname =null, @dbg int =0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @blob is null goto help select * from fn__str_unpattern(@blob,@filter,@opt) goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope wrapper for fn__str_unpattern, extract not repetitive words Parameters @blob the big text @filter value for option @opt options like keep only lines the like @filter unlike exclude lines that not like @filter Examples sp__str_unpattern '''' Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 101 error(-811561914) "local object "FN_GET_2OF5_CHECKDIGIT" is different" in "sp__script_alias" Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 102 error(-811561914) "local object "FN_GET_3OF9_CHECKDIGIT" is different" in "sp__script_alias" Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103 error(-811561914) "local object "FN_GET_ID_ENTITY_FROM_CD_ERP_SHIPMENT" is different" in "sp__script_alias" Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103 error(-811561914) "local object "SP_MANAGE_MAIL_QUEUE" is different" in "sp__script_alias" Messaggio 50000, livello 16, stato 1, procedura sp__err, riga 103 error(-811561914) "local object "SP_REFRESH_VIEWS" is different" in "sp__script_alias" '''',''''[0-9]%'''',''''unlike'''' -- excludes 101 and 102 '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__str_unpattern' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__str_unpattern: -- =================================================================== sp__style select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__style',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130909.0901 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__style') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__style') with nowait goto skip_sp__style end if @ver>130909.0901 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__style') with nowait goto skip_sp__style end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__style') with nowait if exists( select top 1 null from sys.objects where name='sp__style' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__style] begin try exec dbo.sp_executesql @statement = N'/* Keep this due MS compatibility l:see LICENSE file g:utility v:130909.0901,130906\s.zaglio: better help;added shortcut into v:130707\s.zaglio: added a and j tag v:130416\s.zaglio: added more help v:130127\s.zaglio: added tag o and b v:130107\s.zaglio: added lower/upper case in setup option v:121202\s.zaglio: optimized v:121118.1900\s.zaglio: added object based template v:121118\s.zaglio: changed proc style to support exceptions v:121115\s.zaglio: added AC v:121031\s.zaglio: section #tbls init v:121029\s.zaglio: test mode v:120920\s.zaglio: added setup v:120918\s.zaglio: adapted to new script_template v:120906\s.zaglio: added unpvt and procie v:120831.1500\s.zaglio: improve of PROC v:120823\s.zaglio: added func v:120724\s.zaglio: added cursor template r:120625\s.zaglio: a total remake t:sp__style ''proc#SP_TEST'',@opt=''select'' t:sp__style ''setup'' -- sp__style ''procie'' t:sp__style ''func#test'' t:sp__style ''h'' -- sp__style ''header'' */ CREATE proc [dbo].[sp__style] @params sql_variant=null, @opt sysname=null, @dbg smallint=null as begin set nocount on declare @proc sysname, -- for sp__trace @ret int, -- standard API: 0=OK else STATUS(negative if failed) @err int -- user for pure sql statements select @proc=object_name(@@procid),@ret=0,@err=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|''), @dbg=isnull(@dbg,0) declare @p1 sysname, @p2 sysname, @p3 sysname, @p4 sysname, @psep char(1), @procbody sysname, @excludes sysname, @dt datetime create table #tpi( name sysname, params sysname, description sysname, section sysname null ) create table #src (lno int identity primary key,line nvarchar(4000)) create table #vars (id nvarchar(16),value sql_variant) create table #tpl (lno int identity primary key,line nvarchar(4000)) create table #tpl_sec(lno int identity,section sysname,line nvarchar(4000)) create table #tpl_cpl( tpl binary(20),section sysname,y1 int,y2 int, constraint pk_tpl_cpl primary key (tpl,section) ) -- ===================================================================== init == if @dbg>0 exec sp__elapsed @dt out,''-- begin'' select @psep=''#'' -- name params description section insert #tpi select ''proc'', ''name'', ''stored procedure'', null insert #tpi select ''prec'', ''name'', ''stored procedure without except.'', null insert #tpi select ''procwnt'',''name'', ''stored proc. with nested trans.'', ''proc'' insert #tpi select ''procio'',''name'', ''sp for I/O'', ''proc'' insert #tpi select ''procie'',''name'', ''sp for Import/Export'', ''proc'' insert #tpi select ''cs'', ''name'', ''cursor'', null insert #tpi select ''func'', ''name'', ''function'', null insert #tpi select ''h'', '''', ''header'', ''header'' insert #tpi select ''header'','''', ''header'', null insert #tpi select ''unpvt'', '''', ''unpivot table code'', ''unpivot'' insert #tpi select ''setup'', ''grp'', ''sp for setup of group'', null insert #tpi select ''ac'', ''tbl'', ''script alter constraint'', null if @params is null goto help -- ############################################################### templates ## exec sp__Script_template '' %proc%: /* leave this l:see LICENSE file g:[%groups%] k:[%keywords%] r:%builid%: short comment t:one line test t: multi line test */ create proc %proc_name% @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on set xact_abort on --|ntrn| declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''''''), @opt=case when @opt is null then ''''||'''' else dbo.fn__str_quote(@opt,''''|'''') end -- @param=nullif(@param,''''''''), -- nested transaction management --|ntrn| declare @trancount int --|ntrn| select @trancount = @@trancount --|ntrn| if @trancount = 0 --|ntrn| begin transaction --|ntrn| else --|ntrn| save transaction %proc_name% --|ntrn| --|ntrn| -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''''|sel|'''',@opt),@print=charindex(''''|print|'''',@opt), @run=charindex(''''|run|'''',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @run=0 goto help /* test if is it the test or development environment and --|body| if not specified TEST option give an error because the sp can --|body| steal data from production --|body| if dbo.fn__config(''''%app_test_code%'''','''') in (''''test'''',''''dev'''') --|body| and charindex(''''|test|'''',@opt)=0 --|body| begin --|body| raiserror(''''to run in test/dev env. need TEST option'''',16,1) --|body| goto err --|body| end --|body| */ --|body| -- =============================================================== #tbls init == -- ===================================================================== body == %proc_body% -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'''' Scope [write here a short desc] Parameters [param] [desc] @opt options @dbg debug level 1 basic info and do not execute dynamic sql 2 more details (usually internal tables) and execute dsql 3 basic info, execute dsql and show remote info Examples [example] '''' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" --|ntrn| declare @xstate int --|ntrn| select @xstate = xact_state(); --|ntrn| if @xstate = -1 --|ntrn| rollback; --|ntrn| if @xstate = 1 and @trancount = 0 --|ntrn| rollback --|ntrn| if @xstate = 1 and @trancount > 0 --|ntrn| rollback transaction usp_my_procedure_name; --|ntrn| exec @ret=sp__err @cod=@proc,@opt=''''ex'''' return @ret end catch -- proc %proc_name% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %prec%: /* leave this l:see LICENSE file g:[%groups%] k:[%keywords%] r:%builid%: short comment t:one line test t: multi line test */ create proc %proc_name% @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''''''),''''|'''') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @end_declare bit -- =========================================================== initialization == select -- @opt1=charindex(''''|opt|'''',@opt), @end_declare=1 -- ======================================================== second params chk == if @opt=''''||'''' -- charindex(''''|run|'''',@opt)=0 and dbo.fn__isjob(@@spid)=0 -- if can run from a job --|body| goto help /* test if is it the test or development environment and --|body| if not specified TEST option give an error because the sp can --|body| steal data from production --|body| if dbo.fn__config(''''%app_test_code%'''','''') in (''''test'''',''''dev'''') --|body| and charindex(''''|test|'''',@opt)=0 --|body| begin --|body| select @e_msg=''''to run in test/dev env. need TEST option'''' --|body| goto err --|body| end --|body| */ --|body| -- =============================================================== #tbls init == -- ===================================================================== body == %proc_body% -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''''write here msg'''' goto err err_me2: select @e_msg=''''write this %s'''',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'''' Scope [write here a short desc] Parameters [param] [desc] Examples [example] '''' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc %proc_name% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %header%: /* leave this l:see LICENSE file g:[%groups%] k:[%keywords%] r:%builid%: short comment t:one line test */ create -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %cursor%: declare %cs% cursor local for select %%flds%% from %%tbl%% where 1=1 open %cs% while 1=1 begin fetch next from %cs% into %%vars%% if @@fetch_status!=0 break end -- cursor %cs% close %cs% deallocate %cs% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %func%: /* leave this l:see LICENSE file g:[%groups%] k:[%keywords%] r:%builid%: short comment t:one line test */ create function %name%( -- @opt sysname = null, -- @dbg int=0 ) -- returns type -- returns table @t(id int identity,...) -- returns table as select ... as begin declare @ret type select @ret= return @ret end -- %name% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %body%: -- ... -- if ??? goto err_sample -- ... -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %bodyio%: -- 1. input 1 row of data by params -- 2. input 1 or more rows of data by #tbl of same structure os returned rs -- 3. set command for: list, delete (ins, upd are deduced) -- 4. load data into internal normalized tables -- 5. ins/upd/del internal tables -- 6. upd/ins/del storage with internal tables -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %bodyie%: -- 1. import remote files and keep a local copy -- 2. process files into #temp -- 3. create middle tables and find correct PKey 3.1 the name of source file cannot be part of the PK 3.2 if the source file has a progressive, set regression as errors -- 4. do other control -- 5. send reports to technichan -- 6. copy existing in a flat history file -- 7. ins/upd new records on PK in a middle table -- 8. eventually update remote files info renaming in .OK or .ERR -- 9. reupdate middle data with codes associations -- 10. ins/upd final data with last updates -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %unpivot%: select col, val from ( select cast(ca as sql_variant) as ca, cast(cb as sql_variant) as cb from ( select 1 as ca, 2 as cb union all select 3 as ca, 4 as cb ) my_table ) as t unpivot ( val for col in (ca, cb) ) as unpvt -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %setup%: /* leave this l:see LICENSE file g:[%groups%] k:[%keywords%] r:%builid%: setup objects for group %grp% t:%grp%_setup @opt=''''run'''' */ create proc %grp_ssp% @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''''''),''''|'''') -- ========================================================= param formal chk == if charindex(''''|run|'''',@opt)=0 and dbo.fn__isjob(@@spid)=0 goto help -- ============================================================== declaration == declare @util_ver sysname -- =========================================================== initialization == select -- select dbo.fn__group_version(''''utility'''') @util_ver=dbo.fn__group_version(''''utility'''') -- ======================================================== second params chk == if @util_ver<''''%utility_ver%'''' goto err_ver -- ===================================================================== body == exec sp__printf ''''-- %s: utility version is:%d'''',@proc,@util_ver -- ============================================= add base data if 1st install == -- if not exists(select * from %table% where ...) -- if and not object_id(%sp%) is null exec ... -- sp__printf''''do others'''' -- ============================================================== install job == /* -- sp_setup_job get app name, smtp and support emails and call "sp__job" if not object_id(''''sp_setup_job'''') is null -- local application job initializer exec sp_setup_job ''''%action%'''',''''sp_%action%'''',''''%at%'''' --,@grp=''''%grp%'''' */ -- ================================================================== dispose == dispose:if @@trancount>0 rollback goto ret -- =================================================================== errors == err_ver: exec @ret=sp__err ''''please update to latest utility version'''',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'''' Scope called before execute group script and after, create table and populate data Notes this sp must be reentrant because is called before script where tables and stored do not exists and after and a second time again; so must use exists and object_id to test presence of data and objects Parameters @opt options run to execute it (run automatically if executed from job) Examples '''' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc %grp_ssp% -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %ac%: alter table [%tbl%] drop constraint %constraint% alter table [%tbl%] add constraint %constraint% default (%val%) for %column% '' -- ############################################################### templates ## if @dbg>0 exec sp__elapsed @dt out,''-- after templates'' -- ===================================================================== body == select @p1=dbo.fn__str_at(convert(sysname,@params),@psep,1) select @p2=dbo.fn__str_at(convert(sysname,@params),@psep,2) select @p3=dbo.fn__str_at(convert(sysname,@params),@psep,3) select @p4=dbo.fn__str_at(convert(sysname,@params),@psep,4) if @dbg>0 exec sp__printf ''-- 1:%s, 2:%s, 3:%s, 4:%s'',@p1,@p2,@p3,@p4 if not object_id(@p1) is null begin -- template base on similar object, excluding body section exec sp__script @p1 -- script the obj to #src update #src set line=replace(line,@p1,isnull(nullif(@p2,''''),''%new_name%'')) delete from #src where lno> (select lno from #src where line like ''%= body =%'') and lno< (select lno from #src where line like ''%= dispose =%'') exec sp__print_table ''#src'' goto ret end -- object based template -- common macro insert #vars select ''%builid%'',convert(sysname,getdate(),12)+''\%''+system_user+''%'' if @p1=''setup'' insert #vars select ''%utility_ver%'',dbo.fn__group_version(''utility'') -- alter here info for common sections select @procbody=case @p1 when ''procio'' then ''%bodyio%'' when ''procie'' then ''%bodyie%'' else ''%body%'' end select @excludes=replace(@procbody,''%'','''') if @p1!=''procwnt'' select @excludes=@excludes+''|ntrn'' -- get main section select @p1=isnull(section,name) from #tpi where name=@p1 if @dbg>0 exec sp__elapsed @dt out,''-- after inits'' -- main sections process if @p1=''proc'' begin if isnull(@p2,'''')='''' select @p2=''not_specified'' insert #vars select ''%proc_name%'',@p2 exec sp__script_template @procbody,''%proc_body%'',@excludes=@excludes end -- proc if @p1=''prec'' begin if isnull(@p2,'''')='''' select @p2=''not_specified'' insert #vars select ''%proc_name%'',@p2 exec sp__script_template @procbody,''%proc_body%'',@excludes=@excludes end -- prec if @p1=''func'' begin if isnull(@p2,'''')='''' select @p2=''not_specified'' insert #vars select ''%name%'',@p2 exec sp__script_template ''%bodyio%'',''%body%'',@excludes=@excludes end -- proc if @p1=''cs'' begin select @p1=''cursor'' if isnull(@p2,'''')='''' select @p2=''cs'' insert #vars select ''%cs%'',@p2 end -- proc if @p1=''setup'' begin -- sp__style ''setup#test'' -- sp__style ''setup#TEST'' if isnull(@p2,'''')='''' select @p2=''%grp%'' insert #vars select ''%grp%'',@p2 if @p2=lower(@p2) collate SQL_Latin1_General_CP850_BIN select @p2=@p2+''_setup'' else select @p2=@p2+''_SETUP'' insert #vars select ''%grp_ssp%'',@p2 end -- proc if @p1=''ac'' begin -- sp__style ''ac#tbl'' if isnull(@p2,'''')='''' select @p2=''%tbl%'' insert #vars select ''%tbl%'',@p2 end -- ac select @p1=''%''+@p1+''%'' if @dbg>0 exec sp__elapsed @dt out,''-- after templating'' exec sp__script_template @p1,@excludes=@excludes if @dbg>0 exec sp__elapsed @dt out,''-- after mixing'' if charindex(''|select|'',@opt)>0 select line from #src order by lno else exec sp__print_table ''#src'' if @dbg>0 exec sp__elapsed @dt out,''-- after print'' goto ret /* =============================== errors ================================= */ err: -- init of error management /* ================================ help ================================== */ help: -- sp__style exec sp__usage @proc,@extra='' Comment tag styles v:one line short Version comment r:short Release comment t:single test line t: --example of multiple exec sp__printf ''''test line'''' c:single or multile Comment line g:%group1%[,%group2%[,...]] s:See also,... d:deprecated target function (see notes) o:obsolete tag means that this object replaces the obj_name (see notes) k:%keywords% a:%alias% tag compile the object into a synonym of %alias%(if exists) j:reserved for future use for jobs b:%buildin% (not with common know mean) that align the date-version system to application/platform versioning system (see notes) p:profile Press F6 CTRL+A CTRL+C F6 CTRL+A CTRL+V to copy & paste result *** this is the better way (the 4th experimented in 3 years of develop), in mssql200x, to develop test and debug tsql code Notes * I normally associate this sp to shortcut CTRL+8 * Tag V,R v:yymmdd[.hhmm][,old_ver]\author: comment[;comment of old_ver] Examples v:121104\s.zaglio: this is a tipical comment v:121103,121102\s.zaglio: this is the 121103 comment; this of 121102 * Tag K On tag "k" do not repeat groups; do not use more that 4,5 keywords; do not use implicit or deductible words. * Tag D d:yymmdd\u.name:obj_name will delete obj_name on next sp__script_group The lst obj_name "V" tag can contain the motivation * Tag O o:yymmdd\u.name:obsolete_obj_name when an object is still used, cannot be deprecated so temporarily is marked as obsolete from current object; in the future will change to D tag * Tag b b:ver.rel.builin|modifiers can be used by an application/platform utility to place inform the sp__script_group to place the script into a specific place * Tag a see for example fn__hex that is a duplicate of new ms sys.fn_varbintohexstr or fn__str_table_fast that is a duplicate of fn__str_split * Tag p specilize the profile (or target or customer) List of templates '' exec sp__select_astext ''#tpi'',@header=1 select @ret=-1 -- generic Help error ret: -- procedure end...is better than return return @ret end -- sp__style' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__style: -- ===================================================================== sp__svn select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__svn',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090910 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__svn') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__svn') with nowait goto skip_sp__svn end if @ver>090910 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__svn') with nowait goto skip_sp__svn end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__svn') with nowait if exists( select top 1 null from sys.objects where name='sp__svn' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__svn] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090910\s.zaglio: added output of all script of cur db to svn r:090302\S.Zaglio: interface bewteen mssql and svn */ CREATE proc [dbo].[sp__svn] @obj sysname,@svr sysname,@uid sysname,@pwd sysname as begin /* xp_cmdshell ''svn help list'' xp_cmdshell ''svn ls svn://lupin/SOURCES/ -r HEAD'' -- sp__find ''svn://lupin/SOURCES'' -- list content recursivelly -- sp__find ''svn://lupin/SOURCES/\*.vb'' -- set and do a download (populate system table fnd) -- sp__find -- list active downloads xp_cmdshell ''svn ls svn://lupin/SOURCES/SINTESI/trunk -r HEAD -R -v'' --username stefano --password prova'' xp_cmdshell ''svn ls svn://lupin/SOURCES/SINTESI/trunk -r HEAD -R --xml'' --username stefano --password prova'' 71106 davide set 16 09:46 PDA/Build/ 68797 giovanni mag 19 2011 PDA/Build/Argos/ 68594 giovanni 1631 mag 06 2011 PDA/Build/Argos/config.xml Con --verbose i seguenti campi verranno mostrati per ogni elemento: Numero di revisione dell''ultimo commit Autore dell''ultimo commit Se bloccato, la lettera ''O''. (Usa ''svn info URL'' per i dettali) Dimensioni (in byte) Data e ora dell''ultimo commit sp__script ''sp__script'',@out=''src__sp_script.sql'',@dbg=1 -- out to %temp%\...sql sp__run_cmd ''c:\programmi\svn\bin\svn.exe help'',@dbg=1 -- ??? sp__run_cmd ''c:\programmi\svn\bin\svn.exe help update'',@dbg=1 -- ??? sp__run_cmd ''dir /a "c:\Documents and Settings\all users\desktop" /s'' -- brutal remove sp__run_cmd ''rmdir /q /s "c:\Documents and Settings\all users\desktop\ramses"'' -- checkout xp_cmdshell ''svn checkout svn://lupin/SOURCES/SINTESI/ "%temp%\sp__find" -r HEAD --depth infinity ''--username stefano --password prova'' xp_cmdshell ''svn help checkout'' xp_cmdshell ''dir /s %temp%\sp__find'' xp_cmdshell ''rmdir /q /s %temp%\sp__find'' -- cleanup sp__run_cmd ''c:\programmi\svn\bin\svn.exe cleanup "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db"'' -- test existance sp__run_cmd ''c:\programmi\svn\bin\svn.exe ls svn://gamon/PROJECTS/RAMSES/Sviluppo/DB/readme.txt'',@dbg=1 -- ??? sp__run_cmd ''c:\programmi\svn\bin\svn.exe ls svn://gamon/PROJECTS/RAMSES/Sviluppo/DB/this_dont_exist.txt'',@dbg=1 -- ??? -- add new that already exists sp__run_cmd ''c:\programmi\svn\bin\svn.exe add "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db\readme.txt"'',@dbg=1 -- ??? sp__run_cmd ''c:\programmi\svn\bin\svn.exe add "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db\i_dont_exist.txt"'',@dbg=1 -- ??? -- try add new sp__run_cmd ''echo test from sp__svn>"c:\Documents and Settings\all users\desktop\ramses\sviluppo\db\test.txt"'' sp__run_cmd ''c:\programmi\svn\bin\svn.exe add "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db\test.txt"'',@dbg=1 -- ??? sp__run_cmd ''c:\programmi\svn\bin\svn.exe commit "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db" -m "one commit test"'' sp__run_cmd ''echo test change from sp__svn>>"c:\Documents and Settings\all users\desktop\ramses\sviluppo\db\test.txt"'' -- do again add and commit sp__run_cmd ''c:\programmi\svn\bin\svn.exe update "c:\Documents and Settings\all users\desktop\ramses\sviluppo\db"'' -- to see the user sp__run_cmd ''set'' */ print ''to do'' goto ret ret: end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__svn: -- ========================================================= sp__sysobjects_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__sysobjects_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131002 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__sysobjects_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__sysobjects_test') with nowait goto skip_sp__sysobjects_test end if @ver>131002 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__sysobjects_test') with nowait goto skip_sp__sysobjects_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__sysobjects_test') with nowait if exists( select top 1 null from sys.objects where name='sp__sysobjects_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__sysobjects_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:fn__script_drop,fn__sysobjects v:131002,131001\s.zaglio: test for fn__script_drop.fn__sysobjects t:sp__sysobjects_test @opt=''run'' */ CREATE proc sp__sysobjects_test @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @row_id int,@drop_script nvarchar(512),@if_exists nvarchar(512), @sql nvarchar(max),@run bit -- =========================================================== initialization == select @run=charindex(''|run|'',@opt) if @run=0 goto help -- ======================================================== second params chk == -- =============================================================== #tbls init == -- ===================================================================== body == -- drop table #tmp select identity(int,1,1) row_id, *, cast(null as nvarchar(2000)) drop_script_status, cast(null as nvarchar(2000)) if_exists_status into #tmp -- select * from fn__sysobjects(default,default,''drop_script|if_exists'') where obj!=''log_ddl'' -- give error in sp__script_store -- where drop_Script like ''%fn__ntext%'' order by obj,typ update #tmp set if_exists=replace(replace(if_exists,char(13),'' ''),char(10),'' '') while exists(select top 1 null from #tmp where charindex('' '',if_exists)>0) update #tmp set if_exists=replace(if_exists,'' '','' '') while exists(select top 1 null from #tmp where charindex('' )'',if_exists)>0) update #tmp set if_exists=replace(if_exists,'' )'','')'') while exists(select top 1 null from #tmp where charindex(''( '',if_exists)>0) update #tmp set if_exists=replace(if_exists,''( '',''('') exec sp__script_store @opt=''dis'' -- disable declare cs cursor local for select row_id,drop_Script,if_exists from #tmp -- select * from fn__sysobjects(default,default,''drop_script|if_exists'') where 1=1 -- and obj=''fn__ntext_to_lines'' and not if_exists is null and not drop_script is null and not typ in (''D''/*constraint*/, ''SQ''/*service queue*/, ''IT''/*internal table*/, ''FS''/*clr fn*/) and not isnull(parent_typ,'''') in (''IT'') and not (typ=''PK'' and parent_typ!=''U'') open cs while 1=1 begin fetch next from cs into @row_id,@drop_script,@if_exists if @@fetch_status!=0 break -- test if exists select @sql='' select @err_msg=null begin tran savepoint begin try ''+@if_exists+'' select @err_msg=''''ok'''' else select @err_msg=''''ko'''' rollback end try begin catch select @err_msg=''''ko:''''+error_message()+''''(''''+error_procedure()+'''')'''' if @@trancount>0 rollback tran savepoint end catch'' exec sp_executesql @sql,N''@err_msg nvarchar(2000) out'',@err_msg=@err_msg out if @err_msg is null raiserror(''inside error'',16,1) -- if @err_msg=''ko'' exec sp__printsql @sql update #tmp set if_exists_status=@err_msg where row_id=@row_id -- test drop select @sql='' select @err_msg=null begin tran savepoint begin try ''+@drop_script+'' select @err_msg=''''ok'''' rollback end try begin catch select @err_msg=''''ko:''''+error_message()+''''(''''+error_procedure()+'''')'''' if @@trancount>0 rollback tran savepoint end catch'' exec sp_executesql @sql,N''@err_msg nvarchar(2000) out'',@err_msg=@err_msg out -- if @err_msg!=''ok'' exec sp__printsql @sql if @err_msg is null raiserror(''inside error'',16,1) update #tmp set drop_script_status=@err_msg where row_id=@row_id end -- cursor cs close cs deallocate cs select @sql='' select drop_script_status,if_exists_status,sch,obj,typ,[drop], parent,parent_typ,drop_script,if_exists from #tmp order by drop_script_status,if_exists_status,obj,typ '' -- exec(@sql) exec sp__select_astext @sql exec sp__Script_store @opt=''ena'' -- enable if exists(select top 1 null from #tmp where left(drop_script_status,2)=''ko'') raiserror(''test failed'',16,1) -- ================================================================== dispose == dispose: drop table #tmp goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test fn__sysobjects and indirectly fn__script_drop also executing the scripts (into transactions with rollback) Notes ### this sp drop all objects into a transaction that will be rollbacked ### Parameters [param] [desc] @opt options run execute the test @dbg (not used) Examples sp__sysobjects_test @opt="run" '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec sp__Script_store @opt=''ena'' -- disable exec sp__printsql @sql exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__sysobjects_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__sysobjects_test: -- ============================================================ sp__table_2_html select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__table_2_html',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130123 begin if @aut!='L.Mazzanti' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__table_2_html') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__table_2_html') with nowait goto skip_sp__table_2_html end if @ver>130123 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__table_2_html') with nowait goto skip_sp__table_2_html end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__table_2_html') with nowait if exists( select top 1 null from sys.objects where name='sp__table_2_html' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__table_2_html] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility r:130123\L.Mazzanti: stampa in output il testo html di una tabella t: esempio declare @HTML nvarchar(max) set @HTML='''' EXEC SpCustomTable2HTML #tmp, @HTML OUTPUT, ''style="font:8pt" class="AltListBorder" cellpadding="2" cellspacing="1"'', ''class="RowHeader"'' PRINT @HTML */ CREATE PROCEDURE [dbo].[sp__table_2_html] ( @TABLENAME NVARCHAR(500), @OUTPUT NVARCHAR(MAX) OUTPUT, @TBL_STYLE NVARCHAR(1024) = '''', @HDR_STYLE NVARCHAR(1024) = '''') AS BEGIN -- @exec_str stores the dynamic SQL Query -- @ParmDefinition stores the parameter definition for the dynamic SQL DECLARE @exec_str NVARCHAR(MAX) DECLARE @ParmDefinition NVARCHAR(500) --We need to use Dynamic SQL at this point so we can expand the input table name parameter SET @exec_str= N'' DECLARE @exec_str NVARCHAR(MAX) DECLARE @ParmDefinition NVARCHAR(500) --Make a copy of the original table adding an indexing columnWe need to add an index column to the table to facilitate sorting so we can maintain the --original table order as we iterate through adding HTML tags to the table fields. --New column called CustColHTML_ID (unlikely to be used by someone else!) -- select CustColHTML_ID=0,* INTO #CustomTable2HTML FROM '' + @TABLENAME + '' --Now alter the table to add the auto-incrementing index. This will facilitate row finding DECLARE @COUNTER INT SET @COUNTER=0 UPDATE #CustomTable2HTML SET @COUNTER = CustColHTML_ID=@COUNTER+1 -- @HTMLROWS will store all the rows in HTML format -- @ROW will store each HTML row as fields on each row are iterated through -- using dymamic SQL and a cursor -- @FIELDS will store the header row for the HTML Table DECLARE @HTMLROWS NVARCHAR(MAX) DECLARE @FIELDS NVARCHAR(MAX) SET @HTMLROWS='''''''' DECLARE @ROW NVARCHAR(MAX) -- Create the first HTML row for the table (the table header). Ignore our indexing column! SET @FIELDS='''''''' SELECT @FIELDS=COALESCE(@FIELDS, '''' '''','''''''')+'''''''' + name + '''''''' FROM tempdb.sys.Columns WHERE object_id=object_id(''''tempdb..#CustomTable2HTML'''') AND name not like ''''CustColHTML_ID'''' SET @FIELDS=@FIELDS + '''''''' -- @ColumnName stores the column name as found by the table cursor -- @maxrows is a count of the rows in the table, and @rownum is for marking the -- ''''current'''' row whilst processing DECLARE @ColumnName NVARCHAR(500) DECLARE @maxrows INT DECLARE @rownum INT --Find row count of our temporary table SELECT @maxrows=count(*) FROM #CustomTable2HTML --Create a cursor which will look through all the column names specified in the temporary table --but exclude the index column we added (CustColHTML_ID) DECLARE col CURSOR FOR SELECT name FROM tempdb.sys.Columns WHERE object_id=object_id(''''tempdb..#CustomTable2HTML'''') AND name not like ''''CustColHTML_ID'''' ORDER BY column_id ASC --For each row, generate dymanic SQL which requests the each column name in turn by --iterating through a cursor SET @rowNum=0 SET @ParmDefinition=N''''@ROWOUT NVARCHAR(MAX) OUTPUT,@rowNum_IN INT'''' While @rowNum < @maxrows BEGIN SET @HTMLROWS=@HTMLROWS + '''''''' SET @rowNum=@rowNum +1 OPEN col FETCH NEXT FROM col INTO @ColumnName WHILE @@FETCH_STATUS=0 BEGIN --Get nth row from table --SET @exec_str=''''SELECT @ROWOUT=(select top 1 ['''' + @ColumnName + ''''] from (select top '''' + cast(@rownum as varchar) + '''' * from #CustomTable2HTML order by CustColHTML_ID ASC) xxx order by CustColHTML_ID DESC)'''' SET @exec_str=''''SELECT @ROWOUT=(select ISNULL(['''' + @ColumnName + ''''],'''''''''''''''') AS [''''+@ColumnName+''''] from #CustomTable2HTML where CustColHTML_ID=@rowNum_IN)'''' EXEC sp_executesql @exec_str, @ParmDefinition, @ROWOUT=@ROW OUTPUT, @rowNum_IN=@rownum SET @HTMLROWS =@HTMLROWS + '''''''' + @ROW + '''''''' FETCH NEXT FROM col INTO @ColumnName END CLOSE col SET @HTMLROWS=@HTMLROWS + '''''''' END SET @OUTPUT='''''''' IF @maxrows>0 SET @OUTPUT= '''''''' + @FIELDS + @HTMLROWS + ''''
'''' DEALLOCATE col '' DECLARE @ParamDefinition nvarchar(max) SET @ParamDefinition=N''@OUTPUT NVARCHAR(MAX) OUTPUT'' --Execute Dynamic SQL. HTML table is stored in @OUTPUT which is passed back up (as it''s --a parameter to this SP) -- print @exec_str EXEC sp_executesql @exec_str, @ParamDefinition, @OUTPUT=@OUTPUT OUTPUT RETURN 1 END' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__table_2_html: -- ==================================================================== sp__test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130609 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__test') with nowait goto skip_sp__test end if @ver>130609 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__test') with nowait goto skip_sp__test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__test') with nowait if exists( select top 1 null from sys.objects where name='sp__test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,test k:test,sp,case v:130609\s.zaglio: done r:130608\s.zaglio: create case tests t:sp__test ''sp__test'','''',''sp__test'',@dbg=1 -- insert/update unnamed/default t:sp__test ''sp__test'',''.'',''sp__test'' -- error t:sp__test ''sp__test'',''test1'',''sp__test @dbg=1'',@dbg=1 -- insert named t:sp__test ''sp__test'',@opt=''list'' -- exec sp__test ''0x80000027'',@opt=''sel'' t:sp__test ''sp__test'',@opt=''list|sel'' t:sp__test ''sp__test'',@dbg=1 -- test (differ because change the last list t:sp__test ''sp__test'',@name=''%'' t:sp__test ''0x00000002'',@opt=''status'' t:sp__test ''0x00000001'',@opt=''source'' t:sp__test ''0x00000001'',@opt=''result'' t:sp__test ''0x00000002'',@opt=''del'' -- del test t:sp__test ''sp__test_demo'',@opt=''del'' -- purge test t:sp__test ''0x00000001'',@opt=''source|result'' -- error t:truncate table tst */ CREATE proc sp__test @obj sysname = null, @name sysname = null, @tst nvarchar(4000) = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp -- set forceplan off -- (**) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @i int,@n int, -- index, counter @d datetime, @tmp nvarchar(max), -- dynamic sql -- options @opt_list bit, @opt_del bit, @opt_sel bit, @opt_testing bit, @opt_quiet bit, @opt_source bit, @opt_result bit, @opt_status bit, -- summary conditions @opt_detail bit, @purge bit, @disappeared bit, @testing bit, @code nvarchar(max), @result nvarchar(max), @status nvarchar(max), @crlf nvarchar(2), @non_word sysname, @non_sentence sysname, @id int, @rid int, @cmd nvarchar(1024), @err_test sysname, @err_osql sysname, @file nvarchar(1024), @msg nvarchar(1024), -- statuses @sts_untested nchar(2), @sts_passed nchar(2), @sts_error nchar(2), @sts_disappeared nchar(2), @sts_failed nchar(2), @end_declare bit declare @out table (lno int identity primary key, line nvarchar(4000)) -- =========================================================== initialization == select -- constants @crlf=crlf, @rid=power(-2,31), @err_test=''test failed'', @err_osql=''call of sqlcmd failed'', @non_word=non_word, @non_sentence=non_sentence, -- parameters normalization/adjust @obj=nullif(ltrim(rtrim(@obj)),''''), @id=case when left(isnull(@obj,''''),2)=''0x'' then dbo.fn__hex2int(@obj) else null end, @name=case when ltrim(rtrim(@name))='''' then ''default'' else @name end, @tst=nullif(ltrim(rtrim(@tst)),''''), -- options @opt_list=charindex(''|list|'',@opt), @opt_sel=charindex(''|sel|'',@opt), @opt_quiet=charindex(''|quiet|'',@opt), @opt_del=charindex(''|del|'',@opt), @opt_source=charindex(''|source|'',@opt), @opt_result=charindex(''|result|'',@opt), @opt_status=charindex(''|status|'',@opt), @opt_detail=@opt_source|@opt_result|@opt_status, @purge=case when @opt_del=1 and left(@obj,2)!=''0x'' then 1 else 0 end, @testing=case when @tst is null then 1 else 0 end, -- other vars @file=''%temp%\tmp_''+replace(newid(),''-'',''_'')+''.txt'', -- end commodity @end_declare=1 from fn__sym() -- constant/symbol source if not @id is null and @purge=0 select @obj=''%'' select -- statuses constants @sts_untested=''??'', @sts_passed=''ok'', @sts_error=''!#'', @sts_failed=''ko'', @sts_disappeared=''--'' if not @tst is null and (patindex(@non_sentence,@name)>0 or patindex(@non_word,@obj)>0) raiserror(''wild char cannot be used when ins/upd a test'',16,1) -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 if object_id(''tst'') is null begin -- drop table tst drop view tst_list exec('' create table tst( id int identity constraint pk_tst primary key, obj sysname not null, name sysname not null, code nvarchar(4000) not null, result nvarchar(max) not null, status nvarchar(max) not null, ins_dt datetime not null, last_run_dt datetime not null, first_run_ms bigint null, last_run_ms bigint null ) create unique index ix_obj_name on tst(obj,name) '') end -- ======================================================== second params chk == if cast(@opt_source as tinyint)+@opt_result+@opt_status+@opt_del>1 raiserror(''source, result,status and del cannot be specified together'',16,1) if (@opt_list=1 and not @obj is null) or (not @id is null and (@opt_del|@opt_detail)=0) begin select dbo.fn__hex(id) id, obj,name, case when status=@sts_disappeared then ''disappeared'' when status=@sts_untested then ''untested'' when status=@sts_passed then ''passed'' when status=@sts_error then ''error'' else ''failed'' -- containt the two results end as [status], ins_dt,last_run_dt,last_run_ms,first_run_ms into #tmp from tst where obj like isnull(@obj,''%'') and name like isnull(@name,''%'') and (@id is null or id=@id) if @opt_sel=0 exec sp__select_astext ''select * from #tmp order by 2,3'' else select * from #tmp order by 2,3 drop table #tmp goto ret end if not @obj is null goto ac_ins_upd_run -- default action not managed, show help goto help -- =============================================================== #tbls init == ac_ins_upd_run: -- ===================================================================== body == -- scan tests and apply actions specified by parameters or options declare cs cursor local for select id,obj,name,code,result from tst where obj like @obj and name like isnull(@name,''%'') and (@id is null or id=@id) order by obj,name open cs while 1=1 begin fetch next from cs into @id,@obj,@name,@code,@result if @@fetch_status!=0 and @testing=1 break select @disappeared=case when object_id(@obj) is null then 1 else 0 end -- if to delete or purge if @opt_del=1 begin if @purge=1 and @disappeared=0 raiserror(''cannot purge tests of existing objects'',16,1) delete from tst where id=@id if @@rowcount=0 raiserror(''not found'',16,1) exec sp__printf ''-- deleted "%x|%s|%s"'',@id,@obj,@name continue end -- list details of specific test if @opt_detail=1 begin if @opt_source=1 select @tmp=code from tst where id=@id if @opt_result=1 select @tmp=result from tst where id=@id if @opt_status=1 select @tmp=status from tst where id=@id if @opt_sel=0 exec sp__printsql @tmp else select line from fn__ntext_to_lines(@tmp,0) break -- only one test ha sense to show... end select @msg=''|''+left(dbo.fn__hex(@id)+''|''+@obj+''|''+@name +replicate('' '',0),77) if @disappeared=1 begin update tst set last_run_dt=getdate(),status=@sts_disappeared where id=@id select @msg=@sts_disappeared+@msg end else begin -- execute the test and store results select @cmd=''sqlcmd -W -u -E '' -- compact, unicode +''-S "''+@@servername+''" '' +''-d "''+db_name()+''" '' +''-Q "''+isnull(@tst,@code)+''" '' +''-o ''+@file select @tmp='''',@d=getdate() insert @out(line) exec @ret=xp_cmdshell @cmd select @n=datediff(ms,@d,getdate()) if @dbg>0 select lno,line from ( select 0 lno,@cmd as line union select lno,line from @out ) o order by lno if @ret!=0 raiserror(@err_osql,16,1) exec sp__file_read_stream @file,@tmp out,@fmt=''unicode'' -- delete temp file select @cmd=''del /q ''+@file exec @ret=xp_cmdshell @cmd,no_output if @tmp is null raiserror(@err_osql,16,1) if @dbg>0 exec sp__printsql @tmp if patindex(''%Messaggio %, livello %, stato %'',@tmp)>0 or patindex(''%Message %, level %, state %'',@tmp)>0 -- sqlcmd when errors happen or patindex(''HResult %, level %, state %'',@tmp)>0 or patindex(''HResult %, livello %, stato %'',@tmp)>0 select @status=@sts_error else select @status=case @testing when 1 then @sts_passed else @sts_untested end if not @id is null -- update test info begin if @testing=1 and @disappeared=0 begin if @result=@tmp select @msg=@status+@msg else begin if @status=@sts_error select @msg=@sts_error+@msg else select @msg=@sts_failed+@msg select @status =dbo.fn__prints(''80 exec sp__printsql @result select @d=getdate(),@code=@tst,@result=@tmp insert tst(obj,name,code,result,status,ins_dt,last_run_dt,first_run_ms,last_run_ms) select @obj,@name,@code,@result,@status,@d,@d,@n,@n exec sp__printf ''-- inserted "%s"'',@name break end -- insert new test end -- not disappeared if @opt_quiet=0 raiserror(@msg,10,1) end -- cursor cs close cs deallocate cs -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope create case test and store it into tst table; ofcourse can test itself Output ST|NNNNNNNN|OBJ|NAME ST is the status code ?? untested......: just inserted ok passed........: the output is the same !# error.........: inside sql error ko failed........: the output is changed -- disappeared...: the object do not exists NNNNNNNN is the hexadecimal value of id Parameters return 0 for ok; -1 for help; en error code @obj the name of object to test or list or delete (accept %) if an ID (0x...between '''''''') show one line (see option too) @name name/description of the test to run/del (accept %) @tst the test code if different from sp @opt options list get a list of tests with results quiet do not print output sel return data as select instead of print purge willing to @obj, remove tests without existing object del if @obj is 0x... delete the test source if @obj is 0x... show lines of source result if @obj is 0x... show lines of result status if @obj is 0x... show lines of status @dbg debug level 1 show dbg info Examples '' if not object_id(''tst'') is null begin exec sp__printf ''\n-- list of tests grouped by obj --'' exec sp__select_astext ''select obj,count(*) n from tst group by obj order by obj'' end select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch if @@trancount > 0 rollback -- for nested trans see style "procwnt" -- exec sp__printf ''quit:%d, @failed:%s'',@quiet,@failed -- print error_message() exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__test: -- ============================================================= sp__test_server select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__test_server',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090122 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__test_server') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__test_server') with nowait goto skip_sp__test_server end if @ver>090122 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__test_server') with nowait goto skip_sp__test_server end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__test_server') with nowait if exists( select top 1 null from sys.objects where name='sp__test_server' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__test_server] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090122\S.Zaglio: again quoting management and expanded @cmd to 4000 chars v:081124\S.Zaglio: managed names with [] that osql don''t accept v:081114\S.Zaglio: now is indipendent from other my sp to allow simple trasport&run to remote server v:080916\S.Zaglio: a little modification moved @dbg as paramerter v:080806\S.Zaglio: added @db v:080429\S.Zaglio: added @uid & @pwd v:080429\S.Zaglio t: begin declare @r int exec @r=sp__test_server ''10.0.0.228'',''dontexist'' print @r end t: begin declare @r int exec @r=sp__test_server ''.'',''master'' print @r end ->1 t: begin declare @r int exec @r=sp__test_server ''.'',''moster'' print @r end ->0 t: begin declare @r int exec @r=sp__test_server ''.'','''' print @r end ->0 */ CREATE procedure [dbo].[sp__test_server] @svr_name sysname, @db sysname, @ping_method bit=0, -- 0=osql 1=ping @uid sysname=''sa'', @pwd sysname='''', @error nvarchar(4000)=null out, @dbg bit=0 as BEGIN set nocount on declare @exists int declare @crlf nchar(2) SET @crlf=CHAR(13)+CHAR(10) declare @cmd nvarchar(4000) set @exists=0 set @svr_name=dbo.fn__sql_unquotename(@svr_name) set @db=dbo.fn__sql_unquotename(@db) if @ping_method=1 begin if @dbg=1 print ''ping method'' CREATE TABLE #test_svr_temp ( pingResult SYSNAME NULL ); set @cmd=''ping ''+@svr_name if @dbg=1 print @cmd INSERT #test_svr_temp EXEC master..xp_cmdshell @cmd IF EXISTS ( SELECT 1 FROM #test_svr_temp WHERE pingResult LIKE ''%TTL%'' ) set @exists=1 IF @dbg=1 SELECT * FROM #test_svr_temp DROP TABLE #test_svr_temp; end -- ping method else begin -- osql method if @dbg=1 print ''osql method'' IF EXISTS(SELECT 1 FROM dbo.sysobjects WHERE [ID] = OBJECT_ID(''#temp1'') AND type = (''U'')) drop table #temp1 CREATE TABLE #temp1 (dbname SYSNAME NULL ); set @cmd=''osql -S%svr_name% -dMaster -U%uid% -P%pwd% -Q"SELECT [Name] FROM sysdatabases where [name]=''''%db%''''"''; set @cmd=replace(@cmd,''%svr_name%'',@svr_name) set @cmd=replace(@cmd,''%uid%'',@uid) set @cmd=replace(@cmd,''%pwd%'',@pwd) set @cmd=replace(@cmd,''%db%'',@db) if @dbg=1 print @cmd INSERT #temp1 EXEC master..xp_cmdshell @cmd IF EXISTS ( SELECT 1 FROM #temp1 WHERE LTRIM(RTRIM(dbname)) = @db ) set @exists=1 IF @dbg=1 SELECT * FROM #temp1 if @exists=0 begin -- exec sp__readtable ''#temp1'', @error output declare @txt sysname declare @sql nvarchar(4000) declare cs_tmp_svr cursor local for select dbname from #temp1 open cs_tmp_svr while (1=1) begin fetch next from cs_tmp_svr into @txt if @@error != 0 or @@fetch_status != 0 break if coalesce(@error,'''')<>'''' set @error=@error+@crlf set @error=@error+@txt end -- while close cs_tmp_svr deallocate cs_tmp_svr DROP TABLE #temp1 end -- readtable end -- osql method return @exists end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__test_server: -- ============================================================== sp__token_name select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__token_name',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090811 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__token_name') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__token_name') with nowait goto skip_sp__token_name end if @ver>090811 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__token_name') with nowait goto skip_sp__token_name end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__token_name') with nowait if exists( select top 1 null from sys.objects where name='sp__token_name' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__token_name] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090811\s.zaglio: parse next tokens to extract a table path t: declare @path sysname,@s sysname,@i int select @s=''create proc svr.db.[schema].tbl (@param1 int)'',@i=13 exec sp__parse_name @s,@path out,@i out exec sp__printf ''path=%s, next:%d'',@path,@i select @s=''create proc db.[schema].tbl (@param1 int)'',@i=13 exec sp__parse_name @s,@path out,@i out exec sp__printf ''path=%s, next:%d'',@path,@i select @s=''create proc [schema].tbl (@param1 int)'',@i=13 exec sp__parse_name @s,@path out,@i out exec sp__printf ''path=%s, next:%d'',@path,@i select @s=''create proc tbl (@param1 int)'',@i=13 exec sp__parse_name @s,@path out,@i out exec sp__printf ''path=%s, next:%d'',@path,@i */ create proc [dbo].[sp__token_name] @line nvarchar(4000)=null out, -- source code @path sysname =null out, -- output or found and normalized [server].[db].[schema].[name] @start int =null out, -- set/return next position after name @at int =null out, @dbg bit=0 as begin set nocount on declare @token sysname,@tl sysname,@i int,@len int, @svr sysname,@db sysname,@schema sysname,@name sysname select @path=null,@token=null,@tl=''.'',@i=@start,@len=len(@line) exec sp__token @line,@path out,@i out,@at out while @i<=@len and @tl=''.'' begin select @token=null exec sp__token @line,@token out,@i out,@tl=@tl out if @tl=''.'' select @path=@path+@tl+@token,@start=@i end -- select @svr= coalesce(dbo.fn__sql_quotename(parsename(@path,4))+''.'',''''), @db= coalesce(dbo.fn__sql_quotename(parsename(@path,3))+''.'',''''), @schema=coalesce(dbo.fn__sql_quotename(parsename(@path,2))+''.'',''''), @name= coalesce(dbo.fn__sql_quotename(parsename(@path,1)),''''), @path=@svr+@db+@schema+@name end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__token_name: -- =============================================================== sp__top_waits select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__top_waits',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=080918 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__top_waits') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__top_waits') with nowait goto skip_sp__top_waits end if @ver>080918 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__top_waits') with nowait goto skip_sp__top_waits end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__top_waits') with nowait if exists( select top 1 null from sys.objects where name='sp__top_waits' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__top_waits] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:080918\S.Zaglio: originally from http://www.sqldbatips.com/showcode.asp?ID=3 */ CREATE procedure sp__top_waits ( @interval nchar(8) = ''00:00:30'', -- time between snapshots in seconds (1-59) @showall int = 1 -- show all waits longer than this value ) as /* Uses snapshot of waits to determine what''s waiting longest Some help with wait_type can be found at http://support.microsoft.com/default.aspx?scid=kb;en-us;Q244455 Best reference found to date at http://sqldev.net/misc/WaitTypes.htm */ set nocount on create table #waits ( runid int identity(1,1) NOT NULL, wait_type sysname NOT NULL, requests float(53) NOT NULL, wait_time float(53) NOT NULL, signal_wait_time float(53) NOT NULL, CONSTRAINT PK_waits PRIMARY KEY CLUSTERED (runid,wait_type) ) insert #waits exec(''dbcc sqlperf(waitstats)'') waitfor delay @interval insert #waits exec(''dbcc sqlperf(waitstats)'') select a.wait_type,(b.requests-a.requests) as ''requests'', (b.wait_time-a.wait_time) as ''wait_time'', (b.signal_wait_time-a.signal_wait_time) as ''signal_wait_time'' from #waits a join #waits b on a.wait_type = b.wait_type and b.runid>a.runid where (b.wait_time-a.wait_time) >= CAST(@showall as float(53)) and a.wait_type not in (''WAITFOR'', ''SLEEP'', ''RESOURCE_QUEUE'', ''Total'') order by wait_time desc option(KEEPFIXED PLAN) drop table #waits return' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__top_waits: -- ============================================================= sp__trace_event select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__trace_event',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110321 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__trace_event') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__trace_event') with nowait goto skip_sp__trace_event end if @ver>110321 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__trace_event') with nowait goto skip_sp__trace_event end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__trace_event') with nowait if exists( select top 1 null from sys.objects where name='sp__trace_event' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__trace_event] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,sync v:110321\s.zaglio: receive/send messages */ CREATE proc sp__trace_event as begin set nocount on declare @proc sysname,@ret int,@err int,@dbg int select @proc=object_name(@@procid),@ret=0,@err=0,@dbg=isnull(@dbg,0) print ''in sp__trace_event'' while (1=1) begin declare @body nvarchar(max),@type sysname waitfor ( receive top(1) @type=message_type_name, @body=message_body from trace_queue ), timeout 500 -- if there is no message exit if @@rowcount=0 break; if @type=''http://schemas.microsoft.com/SQL/Notifications/PostEventNotification'' begin declare @data xml select @data=cast(@body as xml) declare @et sysname,@obj sysname,@sql nvarchar(max) select @et=EVENTDATA().value(''(/EVENT_INSTANCE/EventType)[1]'',''nvarchar(256)''), @obj=EVENTDATA().value(''(/EVENT_INSTANCE/ObjectName)[1]'',''nvarchar(256)''), @sql=EVENTDATA().value(''(/EVENT_INSTANCE/TSQLCommand)[1]'',''nvarchar(max)'') exec sp__trace_store @et,@obj,@sql end end -- while end -- sp__trace_event' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__trace_event: -- ============================================================= sp__trace_queue select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__trace_queue',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110321 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__trace_queue') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__trace_queue') with nowait goto skip_sp__trace_queue end if @ver>110321 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__trace_queue') with nowait goto skip_sp__trace_queue end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__trace_queue') with nowait if exists( select top 1 null from sys.objects where name='sp__trace_queue' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__trace_queue] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,trace r:110321\s.zaglio:sync scripts with gates and servers */ CREATE proc sp__trace_queue as begin -- exec sp__log ''trace-sync'' print ''some tests but with errors on contract. See code'' goto ret declare @h uniqueidentifier,@b varbinary(max),@t sysname -- select db_name(database_id) db,object_name(queue_id) q,* from sys.dm_broker_queue_monitors -- drop queue sync_queue if object_id(''sync_queue'') is null create queue sync_queue with status=on, activation (procedure_name=sp__sync_queue, max_queue_readers = 1, EXECUTE AS ''tempsa'') -- drop service sync_service create service sync_service on queue sync_queue -- drop route sync_route create route sync_route with service_name=''sync_service'',address=''local'' -- drop message type sync_sql create message type sync_sql -- drop contract sync_contract create contract sync_contract(sync_sql sent by any) alter database utility set enable_broker with rollback immediate -- declare @h uniqueidentifier begin dialog conversation @h from service sync_service to service ''sync_service'' on contract sync_contract with encryption=off print @h -- to prevent error 8429 -- select * from sys.conversation_endpoints /* alter queue trace_queue with status = on , retention = off , activation ( status = off ) alter queue trace_queue with status = on , retention = off , activation ( status = on ) */ -- declare @h uniqueidentifier select @h=''C9E9D502-C553-E011-B483-D48564540B5A'' ;send on conversation @h message type sync_sql(''test queue'') -- select * from sys.transmission_queue -- select db_name(database_id) db,object_name(queue_id) q,* from sys.dm_broker_queue_monitors -- select * from sys.dm_broker_activated_tasks select * from sync_queue select @h=''C9E9D502-C553-E011-B483-D48564540B5A'' ;receive top(1) @h=conversation_handle, @t=message_type_name, @b=message_body from sync_queue print @h print @t print convert(nvarchar(max),@b) print convert(nvarchar(max),convert(xml,@b)) -- declare @h uniqueidentifier select @h=''CFA7D379-A653-E011-B483-D48564540B5A'' end conversation @h -- also prevent error 8429 ret: end -- sp__trace_sync' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__trace_queue: -- ================================================================= sp__tree_fk select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__tree_fk',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081207 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__tree_fk') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__tree_fk') with nowait goto skip_sp__tree_fk end if @ver>081207 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__tree_fk') with nowait goto skip_sp__tree_fk end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__tree_fk') with nowait if exists( select top 1 null from sys.objects where name='sp__tree_fk' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__tree_fk] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:081207\S.Zaglio: get foreing keys hierarchy c:originally from http://www.sqlservercentral.com/scripts/Maintenance+and+Management/30445/ */ create proc sp__tree_fk as begin /****************************************************************************** This script will run through the foreign keys on tables to produce a hierarchy of the tables in a database. The heirarchy produced will be : 0 Tables that have no FK relationships at all, as either as ''parents'' or ''children'' 1 Tables which are at the top of the tree, and have no ''parents'', only ''children'' 2 ...you can figure it out from here... If you need to repopulate the database your table order would be 0,1,2... To delete from tables you need to start at the highest number ...3,2,1,0 *******************************************************************************/ SET NOCOUNT ON DECLARE @intCounter INT, @intRowCount INT CREATE TABLE #Hierarchy (Hierarchy INT, Child VARCHAR(100), Parent VARCHAR(100)) -- Set the variables SELECT @intCounter = 1 SELECT @intRowCount = 1 -- Populate the table INSERT INTO #Hierarchy SELECT DISTINCT 1 AS ''Hierarchy'', S1.name AS ''Child'', SO.Name AS ''Parent'' FROM dbo.sysforeignkeys FK INNER JOIN dbo.sysobjects SO ON FK.rkeyID = SO.id INNER JOIN dbo.sysobjects S1 ON FK.fkeyID = S1.id WHILE @intRowCount <> 0 BEGIN UPDATE #Hierarchy SET Hierarchy = Hierarchy + 1 WHERE Hierarchy = @intCounter AND Parent IN (SELECT DISTINCT Child FROM #Hierarchy WHERE Hierarchy = @intCounter) SET @intRowCount = @@Rowcount SELECT @intCounter = @intCounter + 1 END -- Add the tables that have no Foriegn Key relationships... INSERT INTO #Hierarchy SELECT -1, [name], '' - '' FROM dbo.sysobjects WHERE [name] NOT IN (SELECT DISTINCT Parent FROM #Hierarchy) AND [Name] NOT IN (SELECT DISTINCT Child FROM #Hierarchy) AND xtype = ''U'' -- Add the tables that are Parents only INSERT INTO #Hierarchy SELECT DISTINCT 0, Parent, '' - '' From #Hierarchy WHERE Parent NOT IN (SELECT Child FROM #Hierarchy) AND Hierarchy <> -1 -- Add 1 to adjust the hierarchies to start at 0 UPDATE #Hierarchy SET Hierarchy = Hierarchy + 1 -- Display the results SELECT DISTINCT Hierarchy, Child, Parent FROM #Hierarchy ORDER BY Hierarchy, Child, Parent -- Clean up DROP TABLE #Hierarchy end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__tree_fk: -- ================================================================ sp__triggers select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__triggers',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=090805 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__triggers') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__triggers') with nowait goto skip_sp__triggers end if @ver>090805 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__triggers') with nowait goto skip_sp__triggers end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__triggers') with nowait if exists( select top 1 null from sys.objects where name='sp__triggers' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__triggers] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:090805\S.Zaglio: quotet db name v:080616\S.Zaglio: disable trigger for tables% of optional other db */ CREATE PROCEDURE [dbo].[sp__triggers] @action nchar(2)=''-?'', @tbl_like nvarchar(128)=''%'', @db_dst nvarchar(128)=null AS begin declare @dbg bit set @dbg=0 if @db_dst is null set @db_dst=db_name() select @db_dst=dbo.fn__sql_quotename(@db_dst) declare @sql nvarchar(512) set @tbl_like='' and [name] like ''''''+@tbl_like+'''''''' if @action=''-?'' goto usage if @action=''EA'' -- enable all begin if @dbg=1 print ''enable all triggers for ''+@tbl_like set @sql=''use ''+@db_dst+'' exec sp__foreachobj ''''trigger'''',@replacechar=''''$'''',@command1=''''alter table ? enable trigger $'''',@whereand='''' and parent_obj=object_id(''''''''?'''''''')'''''' if @dbg=1 exec sp__inject @sql out,''print '''''','''''''' exec sp__foreachobj ''TABLE'',@sql,@whereand=@tbl_like end if @action=''DA'' -- disable all begin if @dbg=1 print ''disable all triggers for ''+@tbl_like set @sql=''use ''+@db_dst+'' exec sp__foreachobj ''''trigger'''',@replacechar=''''$'''',@command1=''''alter table ? disable trigger $'''',@whereand='''' and parent_obj=object_id(''''''''?'''''''')'''''' if @dbg=1 exec sp__inject @sql out,''print '''''','''''''' exec sp__foreachobj ''TABLE'',@sql,@whereand=@tbl_like end return usage: print ''sp__triggers'' print '' @action nchar(2)=''''-?'''''' print '' @tbl_like nvarchar(128)=''''%'''''' print '' @db_dst nvarchar(128)=null'' print ''usage:'' print '' sp_t -? this help'' print '' sp_t EA enable all triggers'' print '' sp_t DA disable all triggers'' return test: exec sp__triggers ''DA'',@tbl_like=''a%'' end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__triggers: -- ==================================================================== sp__trim select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__trim',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__trim') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__trim') with nowait goto skip_sp__trim end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__trim') with nowait goto skip_sp__trim end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__trim') with nowait if exists( select top 1 null from sys.objects where name='sp__trim' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__trim] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091018\S.Zaglio: strim chars on left an right from strings s:fn__trim t: declare @st nvarchar(4000),@crlf nchar(2) select @crlf=char(13)+char(10),@st='' select X from Y '' exec sp__trim @st out,@crlf print ''/''+''*''+@st+''*''+''/'' exec sp__trim @st out print ''/''+''*''+@st+''*''+''/'' select @st=''hello world!'' exec sp__trim @st out print ''/''+''*''+@st+''*''+''/'' exec sp__trim @st out,@crlf print @st */ CREATE proc sp__trim @st nvarchar(4000) out, @chars nvarchar(2)='' '' as begin declare @lchars int,@x1 int,@x2 int,@lst int,@c1 nchar(1),@c2 nchar(1) select @c1=substring(@chars,1,1),@c2=substring(@chars,2,1) if @c1='''' and @c2 is null select @st=ltrim(rtrim(@st)) else begin select @lst=len(@st),@lchars=1,@x1=1,@x2=@lst while @x2>0 and substring(@st,@x2,1) in (@c1,@c2) select @x2=@x2-@lchars while @x1<@lst and substring(@st,@x1,1) in (@c1,@c2) select @x1=@x1+@lchars -- print dbo.fn__hex(convert(varbinary(4000),@st)) -- exec sp__printf ''x1=%d,x2=%d'',@x1,@x2 select @st=substring(@st,@x1,@x2-@x1+1) end end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__trim: -- ================================================================ sp__try_exec select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__try_exec',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110705 begin if @aut!='l.mazzanti' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__try_exec') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__try_exec') with nowait goto skip_sp__try_exec end if @ver>110705 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__try_exec') with nowait goto skip_sp__try_exec end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__try_exec') with nowait if exists( select top 1 null from sys.objects where name='sp__try_exec' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__try_exec] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file --optional g:utility r:110705\l.mazzanti: aggiorna l''if_erp_sent, ritentando se necessario t: exec @ret = sp__try_exec ''UPDATE SINTESI_STO11_MOVEMENTS_SN SET IF_ERP_SENT = 10 WHERE IF_ERP_SENT = 101'', 3 */ CREATE PROCEDURE sp__try_exec ( @sql nvarchar(4000), @retries int ) AS BEGIN SET NOCOUNT ON declare @cnt int, @errorset bit select @errorSet=0,@cnt=0 upd_retry: BEGIN TRY IF @cnt<@retries BEGIN SET LOCK_TIMEOUT 10000 exec (@sql) exec sp__printf ''Esecuzione ''''%s'''' | rowcount: %d'', @sql, @@rowcount SET LOCK_TIMEOUT -1 END ELSE BEGIN SET @errorSet = 1 END END TRY BEGIN CATCH SET @cnt = @cnt+1 EXEC sp__printf ''Fallito tentativo n.%s'', @cnt WAITFOR DELAY ''00:00:05'' GOTO upd_retry END CATCH IF @errorSet = 1 return -1 return 0 SET NOCOUNT OFF END' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__try_exec: -- ================================================================== sp__update select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__update',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=081219 begin if @aut!='S.Zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__update') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__update') with nowait goto skip_sp__update end if @ver>081219 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__update') with nowait goto skip_sp__update end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__update') with nowait if exists( select top 1 null from sys.objects where name='sp__update' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__update] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:081219\S.Zaglio: added @rows v:081208\S.Zaglio: done simple random update c:(info at http://msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx) t:sp__update ''ot04_stock'',@excludes=''sync_id,sync_dt'',@random=1,@dbg=1 t:sp__update ''ot04_stock'',@flds=''ID_TRK_PRODUCER'',@where=''sync_id'',@random=1,@dbg=1 */ CREATE proc [dbo].[sp__update] @table sysname, @flds nvarchar(4000)=null,@excludes nvarchar(4000)=null, @values nvarchar(4000)=null, @where nvarchar(4000)=null, @rows bigint=null out, @random bit=0, @dbg bit=0 as begin set nocount on declare @crlf nvarchar(2) set @crlf=char(13)+char(10) declare @sets nvarchar(4000) declare @sql nvarchar(4000) declare @test nvarchar(4000) declare @d datetime set @d=getdate() if @flds is null set @flds=dbo.fn__flds_of(@table,'','',@excludes) if @random=1 begin if @where is null set @where=dbo.fn__flds_of(@table,'','',null) set @sql=''SELECT top 1 ''+@where+'' FROM ''+@table+'' ORDER BY newid() desc'' -- get a random line set @values='''' exec sp__select @sql,@body=@values out,@null=''(/null/)'',@dtstyle=126 set @values=dbo.fn__inject(@values) set @where=replace(@where,'','','' and '') set @where=dbo.fn__str_exp(dbo.fn__str_exp(''%%=''''@@'''''',@where,'' and ''),@values,''|'') set @where=replace(@where,''=''''(/null/)'''''','' is null '') set @sql=''SELECT top 1 ''+@flds+'' FROM ''+@table+'' WHERE ''+@where set @values='''' set @test=''SELECT top 1 ''+@excludes+'' FROM ''+@table+'' WHERE ''+@where exec sp__select @sql,@body=@values out,@null=''(/null/)'',@dtstyle=126 if coalesce(@values,'''')='''' begin print ''error:''+@sql+@crlf+'' ''+dbo.fn__inject(@sql) goto ret end set @values=dbo.fn__inject(@values) set @sets =dbo.fn__str_exp(dbo.fn__str_exp(''%%=''''@@'''''',@flds,'',''),@values,''|'') set @sets=replace(@sets,''=''''(/null/)'''''',''=null '') end if not @where is null set @where ='' where ''+@where else set @where='''' set @sql=''update %tbl%\n set %sets%\n %where%'' exec sp__str_replace @sql out,''\n|%tbl%|%sets%|%where%'',@crlf,@table,@sets,@where if @dbg=1 exec sp__printf @sql exec(@sql) set @rows=@@rowcount if @rows!=1 print ''no updated row'' --exec sp__printf dbo.fn__sql_format(@sql,80) ret: end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__update: -- ================================================================= sp__upgrade select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__upgrade',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130922 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__upgrade') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__upgrade') with nowait goto skip_sp__upgrade end if @ver>130922 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__upgrade') with nowait goto skip_sp__upgrade end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__upgrade') with nowait if exists( select top 1 null from sys.objects where name='sp__upgrade' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__upgrade] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:compare, deploy, upload, download, d:130902\s.zaglio:sp__checkout d:130902\s.zaglio:sp__script_deploy r:130922,130906,130905\s.zaglio:adapting to sp__file_get v:130830\s.zaglio:done remake r:130829\s.zaglio:rename and remake from sp__checkout v:130204\s.zaglio:working near comparation r:130201\s.zaglio:help to identify diff of versions t:sp__upgrade @opt=''list'' */ CREATE proc sp__upgrade @uri nvarchar(max) = null, @opt sysname = null, @dbg int = 0 as begin try -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare @i int,@j int,@n int, @run bit,@noquote bit, @crlf varchar(2),@cr char(1),@lf char(1), @data varbinary(max),@cdata nvarchar(max), -- character data @grp sysname,@temp nvarchar(1024), @todo varchar(16),@obj sysname, @q char,@qq char(2) -- =========================================================== initialization == exec sp__get_temp_dir @temp out select @crlf=crlf,@cr=cr,@lf=lf, @q=''"'',@qq=''""'', @uri=replace(ltrim(rtrim(isnull(@uri,''''))),''%temp%'',@temp), @run=charindex(''|run|'',@opt) from fn__sym() -- ======================================================== second params chk == if @uri='''' goto help if @uri like ''%,%,%,%,%'' select @cdata=@uri,@uri=null if not @uri like ''http%.asmx?op=%'' if not @uri like ''%[\/]index.txt'' raiserror(''@uri must end with "index.txt" file name'',16,1) -- =============================================================== #tbls init == select top 0 * into #objs_list from fn__script_group_select(default,default,default,''top0'',default) -- temp table for index file select top 0 obj,tag,ver,aut,des,lcl into #group_file_list from #objs_list -- drop table #src create table #src(lno int identity primary key,line nvarchar(4000)) -- ===================================================================== body == /* 1. download list (or parse @uri as list) 2. get the group if exists 3. get current list 4. compare ... */ -- ============================================================ download list == -- sp__upgrade ''sp__upgrade,v,130831,s.zaglio,"rename and remake","done remake"'' -- sp__upgrade ''sp__upgrade,v,130831,s.zaglio,"rename and remake","last chglog"'' if @cdata is null begin exec sp__file_get @uri out,@data out select @cdata=cast(@data as nvarchar(max)) end -- fill table and get group name .. if given insert #group_file_list(obj,tag,ver,aut,des,lcl) select c00,c01,c02,c03,c04,c05 from fn__ntext_to_lines(@cdata,0) cross apply fn__str_words(line,'','',''csv'') select @grp=obj from #group_file_list where tag='''' -- ===================================================== fill with local list == insert into #objs_list select * from fn__script_group_select(@grp,default,default,''lcl'',default) -- ======================================================= compare into #todo == -- t:sp__upgrade ''%temp%\utility\index.txt'' select todo= case when ol.obj is null then ''add'' when isnull(ol.lcl,'''')!=isnull(gl.lcl,'''') then ''conflict'' when isnull(ol.lcl,'''')=isnull(gl.lcl,'''') then case when ol.ver>gl.ver then ''newest'' when ol.ver conflict case 4 and 5: if the happen together, there is no way to solve if 4 happen before 5, 5 see a difference the new object with conflict is stored into LOG_DDL and difference can be explored using SP__SCRIPT_DIFF. Parameters @uri is the source of list (see sp__script_group_tofile); can be: - url of "index.txt" (index.txt must be included) - path of "index.txt" (index.txt must be included) - the source of the list (for manual comparision) @opt options run execute the upgrade instead of list the differencies newest add to the output the source of newest objects Examples -- load list from file and compare with local exec sp__upgrade "%temp%\utility\index.txt" -- compare current "sp__upgrade" version with the specified exec sp__upgrade ''''sp__upgrade,v,130829,s.zaglio,"rename and remake"'''' -- '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__upgrade' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__upgrade: -- =================================================================== sp__usage select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__usage',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120824 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__usage') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__usage') with nowait goto skip_sp__usage end if @ver>120824 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__usage') with nowait goto skip_sp__usage end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__usage') with nowait if exists( select top 1 null from sys.objects where name='sp__usage' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__usage] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120824\s.zaglio: added usage of #sp v:120112\s.zaglio: now print @obj version near usage of ... v:110706\s.zaglio: added odd/event test for presence of " v:110628\s.zaglio: a bug near info on fn v:110513\s.zaglio: a small bug v:110510\s.zaglio: replace " with '' on line starting with sp_ v:110507\s.zaglio: replace " with '' if inside sql code v:110422\s.zaglio: expanded @extra to blob v:110406\s.zaglio: added @p1...,@opt, removed old @test params v:110312\s.zaglio: added autoreverse if remote call v:100919.1000\s.zaglio: more compatible mssql2k v:100919\s.zaglio: out of extra without replacement of macro v:100723\s.zaglio: @force=0 in print of @extra (for sp__style) v:100707\s.zaglio: show info about reversed v:100501\s.zaglio: added @reverse v:100404\s.zaglio: added #vars replacements v:100228\s.zaglio: added db name support v:090222\s.zaglio: addded out&null info v:090805\S.Zaglio: removed @force=0 on printf v:090729\S.Zaglio: revision v:090623\S.Zaglio: revision v:090616\S.Zaglio: added @extra v:090610\S.Zaglio: added @print v:090608\S.Zaglio: added -- to use as template for sp call v:090520\S.Zaglio: added more info to params v:081117\S.Zaglio: made indipendent from sp__dir v:081021\S.Zaglio: print a fast & simple expanation of parameters of sp (future expansion) t:sp__usage ''fn__comments'' */ CREATE PROCEDURE [dbo].[sp__usage] @obj sysname=null, @extra ntext=null, -- extra help until will be integrated in a help system @p1 sql_variant=null, @p2 sql_variant=null, @p3 sql_variant=null, @p4 sql_variant=null, @opt sysname=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @obj is null goto help create table #src (lno int identity,line nvarchar(4000)) -- insert #src(line) select ''test'' create table #blob(id int identity,blob ntext) create table #cols(id int identity,name sysname,colorder int) declare @n int,@db sysname,@reverse bit,@id bigint,@sql nvarchar(4000), @sel bit,@xt nvarchar(2),@ver nvarchar(32) select @reverse=dbo.fn__isremote(@@spid), @sel=charindex(''|sel|'',@opt) if left(@obj,1)=''#'' begin select @id=object_id(''tempdb..''+@obj) select @xt=xtype from tempdb..sysobjects with (nolock) where id=@id insert #cols select name,colorder from tempdb..syscolumns c with (nolock) where left(c.name,1)=''@'' end else begin select @id=object_id(@obj) select @xt=xtype from sysobjects with (nolock) where id=@id insert #cols select name,colorder from syscolumns c with (nolock) where left(c.name,1)=''@'' end if @id is null goto err_obj if (@xt) in (''FN'',''TF'',''IF'') begin -- select * from syscolumns where id=object_id(''fn__comment'') -- select * from syscolumns where id=object_id(''fn__comments'') select @sql=null select @sql=isnull(@sql+'','','''')+''/*''+c.[name]+''*/default'' from #cols order by c.colorder if @xt=''IF'' select @sql=''select dbo.''+@obj+''(''+@sql+'')'' select @sql=''select * from [''+@obj+''](''+@sql+'')'' if @sel=1 select @sql else print @sql if @extra is null goto ret end -- select @ver='' (''+tag+'':''+convert(sysname,val1)+'') '' from dbo.fn__script_info(@obj,''rv'',0) select @ver=isnull(@ver,'''') insert #src(line) select ''usage of '' + @obj+@ver+ case @reverse when 1 then ''(list is reversed for remote servers)'' else '''' end -- print parsename(''db..obj'',3) -- print isnull(parsename(''obj'',3),''??'') select @db=parsename(@obj,3) if @db is null select @db=db_name() -- print parsename(''obj'',1) select @obj=parsename(@obj,1) exec('' use [''+@db+''] declare @n int,@obj sysname select @obj=''''''+@obj+'''''' select @n=max(len(name)) from syscolumns with (nolock) where id=object_id(@obj) insert into #src(line) select '''' ''''+left(c.[name]+space(@n),@n) + '''' ''''+case when t.name in (''''nvarchar'''',''''nchar'''') then t.name+''''(''''+convert(sysname,c.length/2)+'''')'''' when t.name in (''''char'''',''''varchar'''') then t.name+''''(''''+convert(sysname,c.length)+'''')'''' else t.name end+ -- case when c.isnullable=1 then ''''=null'''' else '''''''' end+ because all def params are nullable '''' ''''+case when c.isoutparam=1 then ''''out'''' else '''''''' end+ '''','''' as line from syscolumns c with (nolock) inner join systypes t with (nolock) on c.xusertype=t.xusertype where id=object_id(@obj) and left(c.name,1)=''''@'''' order by colid '') insert #blob(blob) select @extra exec sp__write_ntext_to_lines @crlf=0 drop table #blob if not object_id(''tempdb..#vars'') is null exec sp__str_replace ''#src'',''#vars'' update #src set line=replace(line,''%proc%'',@obj) if not @p1 is null update #src set line=replace(line,''%p1%'',convert(nvarchar(4000),@p1,126)) if not @p2 is null update #src set line=replace(line,''%p2%'',convert(nvarchar(4000),@p2,126)) if not @p3 is null update #src set line=replace(line,''%p3%'',convert(nvarchar(4000),@p3,126)) if not @p4 is null update #src set line=replace(line,''%p4%'',convert(nvarchar(4000),@p4,126)) -- replace " with '' if even occurrences and in particular cases update #src set line=replace(line,''"'','''''''') where 1=1 and (charindex(''"'',line)>0 and dbo.fn__str_count(line,''"'')%2=1) and ( charindex('' '',ltrim(line))>0 and ( left(ltrim(line),charindex('' '',ltrim(line))-1) in (''select'',''insert'',''exec'',''if'',''else'',''update'',''declare'',''set'') or left(ltrim(line),3)=''sp_'' ) or left(ltrim(line),1)=''@'' ) if @sel=1 select line from #src order by lno else -- print exec sp__print_table ''#src'',@reverse=@reverse drop table #src goto ret -- =================================================================== errors == err_obj: exec @ret=sp__err ''object not found'' goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope of %proc% Version 1.04.110406 print info and help about an object Notes * if the object is a function, add a line of code with its call * if called remotelly, print help in reverse order (MS remote print problem) * if declare #vars, inside tokens are replaced (see sp__str_replace) * ********************************************* * ** this help is a template for all others ** * ********************************************* * future strategy is to use this sp to populate wiki table * in the lines that start with "exec","select",etc or "sp_" is considered sql code and " will be replaced with '''' Parameters @obj name of object @extra info/help text if @extra contain macros, this will be replaced macro mean %proc% replaced with @obj %p1% replaced with @p1 %p...% replaced with @p... @opt options sel return help as select instead of print Examples exec sp__usage ''''sp__usage'''','''' Scope of %obj% this is an examples with replace %p1% '''', @p1=''''p1_test'''' '' select @ret=-1 ret: return @ret end -- sp__usage' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__usage: -- ============================================================ sp__util_1strace select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_1strace',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=101130 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_1strace') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_1strace') with nowait goto skip_sp__util_1strace end if @ver>101130 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_1strace') with nowait goto skip_sp__util_1strace end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_1strace') with nowait if exists( select top 1 null from sys.objects where name='sp__util_1strace' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_1strace] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:101130\s.zaglio: show current trace info t:select * from ::fn_trace_getinfo(default) */ create proc sp__util_1strace as begin -- SELECT 0, TextData, DatabaseID, ApplicationName, Duration, EndTime, Reads, Writes, CPU select StartTime,EndTime,TextData,Reads, Writes, CPU,* from fn_trace_gettable((select convert(nvarchar(512),[value]) from ::fn_trace_getinfo(default) where traceid=1 and [property]=2), default) where 1=1 and StartTime>getdate()-0.1 and TextData IS NOT NULL end -- sp__util_1strace' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_1strace: -- ============================================================== sp__util_3load select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_3load',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100508 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_3load') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_3load') with nowait goto skip_sp__util_3load end if @ver>100508 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_3load') with nowait goto skip_sp__util_3load end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_3load') with nowait if exists( select top 1 null from sys.objects where name='sp__util_3load' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_3load] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100508\s.zaglio: load/reload data from a remote server, triangulating from a 2nd rmtsvr c: this <- tsvr <- rmtsvr2 t:sp__util_3load ''tbl'',''tsvr'',''rsvr'',@truncate=1,@dbg=1 */ CREATE proc sp__util_3load @tbl sysname=null, @tsvr sysname=null, @rsvr sysname=null, @rdb sysname=null, @truncate bit=1, @err int=null out, @rows bigint=null out, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=''sp__util_3load'',@ret=1 if @tbl is null goto help declare @tmp sysname,@sql nvarchar(4000),@db sysname, @trunc sysname,@sch sysname select @rsvr=dbo.fn__sql_quotename(quotename(@rsvr)), @db=quotename(db),@sch=quotename(sch),@tbl=quotename(obj) from dbo.fn__parsename(@tbl,default,default) select @tbl=@sch+''.''+@tbl if @rdb is null select @rdb=@db select @tmp=''tempdb..tmp_''+dbo.fn__str_guid(newid()) if @truncate=1 select @trunc=''truncate table ''+@tbl select @sql='' use %db% exec %tsvr%.tempdb.dbo.sp_executesql N"select * into %tmp% from %rsvr%.%rdb%.%tbl%" -- dont''''t look at me; it is required to elude a "Deferred prepare could not be completed" exec("select * into %tmp% from openquery(%tsvr%,""select * from %tmp%"")") exec %tsvr%.tempdb.dbo.sp_executesql N"drop table %tmp%" begin tran %truncate% if objectproperty(object_id("%tbl%"),"TableHasIdentity")=1 set identity_insert %tbl% on insert into %tbl% select * from %tmp% select @err=@@error,@rows=@@rowcount if objectproperty(object_id("%tbl%"),"TableHasIdentity")=1 set identity_insert %tbl% off if @err=0 commit else rollback drop table %tmp% '' exec sp__str_replace @sql out, ''"|%db%|%tsvr%|%tmp%|%rsvr%|%rdb%|%tbl%|%truncate%'', '''''''',@db,@tsvr,@tmp,@rsvr,@rdb,@tbl,@trunc if @dbg=1 print @sql else exec sp_executesql @sql,N''@err int out,@rows bigint out'', @err=@err out,@rows=@rows out goto ret help: exec sp__usage @proc,'' Scope load/reload data from a remote server, triangulating from a 2nd rmtsvr '' ret: return @ret end -- sp__util_load' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_3load: -- ============================================================= sp__util_advopt select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_advopt',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100405 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_advopt') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_advopt') with nowait goto skip_sp__util_advopt end if @ver>100405 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_advopt') with nowait goto skip_sp__util_advopt end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_advopt') with nowait if exists( select top 1 null from sys.objects where name='sp__util_advopt' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_advopt] begin try exec dbo.sp_executesql @statement = N'/* leave this g:utility v:100405\s.zaglio: show lòcal ad options v:100228\s.zaglio: activate advanced option on remote linked server t:sp__util_advopt ''.'' */ CREATE proc [dbo].[sp__util_advopt] @svr sysname=null as begin set nocount on if @svr is null goto help declare @sql nvarchar(4000) select @sql='' EXECUTE %svr%..sp_configure "show advanced options", 1 RECONFIGURE WITH OVERRIDE reconfigure EXECUTE %svr%..sp_configure "Ad Hoc Distributed Queries",1 RECONFIGURE WITH OVERRIDE EXECUTE %svr%..sp_configure "xp_cmdshell", "1" RECONFIGURE WITH OVERRIDE EXECUTE %svr%..sp_configure "Ole Automation Procedures", "1" RECONFIGURE WITH OVERRIDE EXECUTE %svr%..sp_configure "SMO and DMO XPs", "1" RECONFIGURE WITH OVERRIDE EXECUTE %svr%..sp_configure "clr enabled", "1" RECONFIGURE WITH OVERRIDE -- MSSQL2008 -- EXECUTE sp_configure "Ad Hoc Distributed Queries",1 RECONFIGURE WITH OVERRIDE EXECUTE %svr%..sp_configure EXECUTE %svr%..sp_configure "show advanced options", 0 RECONFIGURE WITH OVERRIDE reconfigure '' select @sql=replace(@sql,''"'','''''''') if @svr=''.'' select @sql=replace(@sql,''%svr%..'','''') else select @sql=replace(@sql,''%svr%'',''[''+@svr+'']'') exec sp__printf @sql exec(@sql) goto ret help: exec sp__printf ''Enable advanced options (openroset,xp_cmdshell, etc) on remote server'' exec sp__printf ''Use "." on local server'' EXECUTE sp_configure "show advanced options", 1 RECONFIGURE WITH OVERRIDE reconfigure EXECUTE sp_configure EXECUTE sp_configure "show advanced options", 0 RECONFIGURE WITH OVERRIDE reconfigure ret: end -- sp__util_advopt' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_advopt: -- ======================================================== sp__util_auto_growth select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_auto_growth',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130227 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_auto_growth') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_auto_growth') with nowait goto skip_sp__util_auto_growth end if @ver>130227 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_auto_growth') with nowait goto skip_sp__util_auto_growth end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_auto_growth') with nowait if exists( select top 1 null from sys.objects where name='sp__util_auto_growth' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_auto_growth] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:monitor,database,performance,auto,grouth v:130227\s.zaglio: identifying how often an auto-growth event has occurred c: from https://www.simple-talk.com/sql/database-administration/sql-server-database-growth-and-autogrowth-settings/ t:sp__util_auto_growth run */ create proc sp__util_auto_growth @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare -- generic common @run bit, -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @sel bit,@print bit, -- select and print option for utils @end_declare bit -- =========================================================== initialization == select -- @sel=charindex(''|sel|'',@opt),@print=charindex(''|print|'',@opt), @run=charindex(''|run|'',@opt)|dbo.fn__isjob(@@spid) |cast(@@nestlevel-1 as bit), -- when called by parent/master SP @end_declare=1 -- if @print=0 and @sel=0 and dbo.fn__isConsole()=1 select @print=1 -- ======================================================== second params chk == if @run=0 goto help -- =============================================================== #tbls init == -- ===================================================================== body == declare @filename nvarchar(1000); declare @bc int; declare @ec int; declare @bfn varchar(1000); declare @efn varchar(10); -- get the name of the current default trace select @filename = cast(value as nvarchar(1000)) -- select * from ::fn_trace_getinfo(default) where traceid = 1 and property = 2; -- rip apart file name into pieces set @filename = reverse(@filename); set @bc = charindex(''.'',@filename); set @ec = charindex(''_'',@filename)+1; set @efn = reverse(substring(@filename,1,@bc)); set @bfn = reverse(substring(@filename,@ec,len(@filename))); -- set filename without rollover number set @filename = @bfn + @efn -- process all trace files select ftg.starttime ,te.name as eventname ,db_name(ftg.databaseid) as databasename ,ftg.filename ,(ftg.integerdata*8)/1024.0 as growthmb ,(ftg.duration/1000)as durms from ::fn_trace_gettable(@filename, default) as ftg inner join sys.trace_events as te on ftg.eventclass = te.trace_event_id where (ftg.eventclass = 92 -- date file auto-grow or ftg.eventclass = 93) -- log file auto-grow order by ftg.starttime -- sp__find ''fn_trace_getinfo'' -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope identifying how often an auto-growth event has occurred Parameters @opt options run execute Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__util_auto_growth' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_auto_growth: -- ======================================================== sp__util_cache_empty select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_cache_empty',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091209 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_cache_empty') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_cache_empty') with nowait goto skip_sp__util_cache_empty end if @ver>091209 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_cache_empty') with nowait goto skip_sp__util_cache_empty end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_cache_empty') with nowait if exists( select top 1 null from sys.objects where name='sp__util_cache_empty' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_cache_empty] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091209\s.zaglio */ create proc sp__util_cache_empty as begin checkpoint; dbcc dropcleanbuffers; end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_cache_empty: -- ======================================================== sp__util_connections select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_connections',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121025 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_connections') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_connections') with nowait goto skip_sp__util_connections end if @ver>121025 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_connections') with nowait goto skip_sp__util_connections end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_connections') with nowait if exists( select top 1 null from sys.objects where name='sp__util_connections' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_connections] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:tcp,ip,host,status,client v:121025\s.zaglio: list active connections and some useful info t:sp__util_connections # t:sp__util_connections ''%hostname%'' */ CREATE proc sp__util_connections @what sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @end_declare bit -- =========================================================== initialization == select -- @opt1=charindex(''|opt|'',@opt), @end_declare=1 -- ======================================================== second params chk == if @what is null goto help -- ===================================================================== body == if @what=''#'' select @what=''%'' else select @what=''%''+@what+''%'' select @what=replace(@what,''%hostname%'',host_name()) select c.session_id, p.kpid, p.lastwaittype,p.waitresource, p.status,p.hostname,p.program_name,p.loginame, db_name(p.dbid) db, c.most_recent_session_id, c.connect_time, c.num_reads, c.num_writes, c.last_read, c.last_write, c.client_net_address, c.client_tcp_port, c.local_net_address, c.local_tcp_port, object_name(s.objectid,s.dbid) obj, substring(s.text,p.stmt_start/2, (case when p.stmt_end = -1 then len(convert(nvarchar(max), s.text)) * 2 else p.stmt_end end - p.stmt_start+3)/2) as sql --most_recent_sql_handle /* SELECT substring(text,x.statement_start_offset/2, (case when x.statement_end_offset = -1 then len(convert(nvarchar(max), text)) * 2 else x.statement_end_offset end - x.statement_start_offset+3)/2) -- select * from FROM sys.dm_exec_sql_text(x.sql_handle) FOR XML PATH(''''), TYPE ) AS Sql_text */ -- select * from sys.dm_exec_connections c (nolock) join sys.sysprocesses p (nolock) on c.session_id=p.spid -- join sys.dm_exec_requests r on c.session_id=r.spid cross apply sys.dm_exec_sql_text(p.sql_handle) as s where 1=1 and p.spid!=@@spid and @what=''%'' or ( p.status like @what or p.hostname like @what or p.program_name like @what or p.loginame like @what or db_name(p.dbid) like @what ) -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == /* err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_me1: select @e_msg=''write here msg'' goto err err_me2: select @e_msg=''write this %s'',@e_p1=@var goto err */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope list active connections and some useful info Parameters @what a generic filter for each text field use # or ''''%'''' for everithing @opt not used @dbg not used Examples t:sp__util_connections # t:sp__util_connections ''''%hostname%'''' '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__util_connections' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_connections: -- ============================================================= sp__util_drives select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_drives',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130802 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_drives') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_drives') with nowait goto skip_sp__util_drives end if @ver>130802 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_drives') with nowait goto skip_sp__util_drives end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_drives') with nowait if exists( select top 1 null from sys.objects where name='sp__util_drives' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_drives] begin try exec dbo.sp_executesql @statement = N'/* leave this l:%licence% g:utility v:130802\s.zaglio: about drop of #drive_info v:130227\s.zaglio: added dbs and logs flds v:130216\s.zaglio: remake v:100212\s.zaglio: drives info c:from http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=92571 t:sp__util_drives run */ CREATE proc sp__util_drives @opt sysname = null, @dbg bit=null as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid), @ret=0, @dbg=isnull(@dbg,0), @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') declare @result int , @objfso int , @drv int , @cdrive nvarchar(13) , @size nvarchar(50) , @free nvarchar(50) , @label nvarchar(10) , @dbs nvarchar(4000) , @logs nvarchar(4000) , @flds nvarchar(4000) , @oid int select @flds='' letter nchar(1), total_mb bigint, free_mb bigint, label nvarchar(10), [% free] int, dbs nvarchar(4000), logs nvarchar(4000) '', @oid=object_id(''tempdb..#drive_info'') -- ============================================================= check params == if charindex(''|run|'',@opt)=0 goto help declare @sysdb table (db sysname) create table #drive_space ( letter nchar(1) not null, freemb nvarchar(10) not null ) if @oid is null begin create table #drive_info(id int identity) exec(''alter table #drive_info add ''+@flds) end insert @sysdb select ''master'' union select ''msdb'' union select ''model'' insert into #drive_space exec master.dbo.xp_fixeddrives -- iterate through drive letters. declare curdriveletters cursor local for select letter from #drive_space declare @driveletter nchar(1) open curdriveletters fetch next from curdriveletters into @driveletter while (@@fetch_status <> -1) begin if (@@fetch_status <> -2) begin select @cdrive = ''getdrive("'' + @driveletter + ''")'' exec @result = sp_oacreate ''scripting.filesystemobject'', @objfso output if @result = 0 exec @result = sp_oamethod @objfso, @cdrive, @drv output if @result = 0 exec @result = sp_oagetproperty @drv,''totalsize'', @size output if @result = 0 exec @result = sp_oagetproperty @drv,''freespace'', @free output if @result = 0 exec @result = sp_oagetproperty @drv,''volumename'', @label output if @result <> 0 exec sp_oadestroy @drv exec sp_oadestroy @objfso select @size = (convert(bigint,@size) / 1048576 ) select @free = (convert(bigint,@free) / 1048576 ) select @dbs=null select @dbs=isnull(@dbs+'' | '','''')+db_name(database_id) -- select * from sys.master_files where physical_name like @driveletter+'':%'' and type=0 and not db_name(database_id) in (select db from @sysdb) select @logs=null select @logs=isnull(@logs+'' | '','''')+db_name(database_id) from sys.master_files where physical_name like @driveletter+'':%'' and type=1 and not db_name(database_id) in (select db from @sysdb) insert into #drive_info(letter,total_mb,free_mb,label,dbs,logs) values (@driveletter, @size, @free, @label,@dbs,@logs) end fetch next from curdriveletters into @driveletter end close curdriveletters deallocate curdriveletters -- produce report. update #drive_info set [% free]=cast(((convert(numeric(9,0),free_mb) /convert(numeric(9,0),total_mb)) * 100) as int) -- if @out is null select @sql='''' else select @sql =''insert ''+@out+'' '' if @oid is null begin select * from #drive_info drop table #drive_info end drop table #drive_space goto ret help: exec sp__usage @proc,'' Scope list drives space info with list of dbs See sp__util_vlf Notes the table #drive_info is used return to caller the data create table #drive_info(%p1%) Parameters @opt options run execute @dbg not used '',@p1=@flds select @ret=-1 ret: return @ret end -- sp__util_drives' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_drives: -- ============================================================= sp__util_gource select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_gource',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120823 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_gource') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_gource') with nowait goto skip_sp__util_gource end if @ver>120823 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_gource') with nowait goto skip_sp__util_gource end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_gource') with nowait if exists( select top 1 null from sys.objects where name='sp__util_gource' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_gource] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120823\s.zaglio: return a custom log for gource d:120823\s.zaglio: sp__script_svn_log t:sp__util_gource @opt=''run|util'' t:sp__util_gource @opt=''run'' */ CREATE proc sp__util_gource @opt sysname=null, @dbg int=0 as begin /* gource.exe --log-format svn -s 0.1 --stop-at-end --max-file-lag 10 --title "TSQL Utility" -640x480 --hide bloom,progress,dirnames --disable-auto-rotate --key --file-idle-time 0 --camera-mode overview utility.xml ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i utility.ppm -vcodec libx264 -preset ultrafast -crf 1 -threads 0 -bf 0 utility.avi */ -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @opt is null or charindex(''|run|'',@opt)=0 goto help -- ============================================================== declaration == declare @sdt sysname,@id int,@d sysname,@t sysname,@dt datetime, @util bit -- insert before here -- @end_declare bit create table #src(lno int identity, line nvarchar(4000)) -- =========================================================== initialization == select @util=charindex(''|util|'',@opt) -- ======================================================== second params chk == -- ===================================================================== body == -- drop table #rel select identity(int,1,1) as id, object_name(obj_id) name, case tag when ''d'' then cast(isnull(val3,val1) as sysname) else obj end as obj, tag, cast(val1 as sysname) as sdt, cast(val2 as sysname) as author into #rel -- select top 100 * from fn__script_info(default,''rvdx'',default) where not obj like ''%[_]old'' if @util=1 delete from #rel where not obj like ''%[_][_]%'' else delete from #rel where obj like ''%[_][_]%'' alter table #rel add dt datetime, unix_timestamp sysname, grp sysname, color int, scolor varchar(6) update #rel set obj=case @util when 1 then substring(obj,charindex(''__'',obj)+2,128) else obj end, grp=case @util when 1 then dbo.fn__str_between(obj,''__'',''_'',default) else dbo.fn__str_between(obj,''_'',''_'',default) end, author=lower(isnull(author, case @util when 1 then ''s.zaglio'' else ''unknown'' end )) update #rel set color=abs(dbo.fn__crc32(grp))/256 update #rel set grp=null,color=5592405*2.8 where grp=obj update #rel set color=color+5592405 where color<5592405 update #rel set scolor=upper(right(dbo.fn__hex(color),6)) delete from #rel where isnumeric(sdt)=0 and tag=''d'' -- select * from #rel where obj is null or isnumeric(sdt)=0 -- select * from #rel where sdt like ''%24.100%'' -- set nocount on -- declare @sdt sysname,@id int,@d sysname,@t sysname,@dt datetime declare cs cursor local for select id,sdt from #rel where 1=1 open cs while 1=1 begin fetch next from cs into @id,@sdt if @@fetch_status!=0 break if @sdt=''000000'' select @sdt=convert(sysname,cast(0 as datetime),12) select @d= dbo.fn__format(left(@sdt,6),''@12-34-56'',default), @t= case when charindex(''.'',@sdt)=0 then ''00:00:00'' else dbo.fn__format(right(@sdt,4),''@12:34'',default)+'':00'' end begin try select @dt=convert(datetime,@d,11)+convert(datetime,@t,8) update #rel set dt=@dt where id=@id end try begin catch exec sp__printf ''-- cannot convert %d:%s(%s,%s)'',@id,@sdt,@d,@t end catch end -- cursor cs close cs deallocate cs -- select * from #rel where id in (379,487) delete from #rel where dt is null update #rel set unix_timestamp=dbo.fn__unix_timestamp(dt) -- 1275543595|andrew|A|src/main.cpp|FF0000 select unix_timestamp + ''|'' + author + ''|'' + case tag when ''d'' then ''D'' else ''M'' end + ''|'' + isnull(grp+''/'','''')+obj + ''|'' + scolor as line from #rel order by dt -- exec sp__print_table ''#src'' drop table #src /* after generation, can use gourge. For me better results are with: gource.exe utility.log -s 0.3 -r 25 --stop-at-end -800x600 --highlight-dirs --font-size 12 --font-colour 0000FF -o utility.ppm --key --title "utility" --max-files 0 --highlight-all-user -i 0 ffmpeg -y -b 3000K -r 30 -f image2pipe -vcodec ppm -i utility.ppm -vcodec libx264 -fpre "e:/share/ffmpeg/libx264-slow.ffpreset" -threads 0 utility.mp4 */ goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope produce a custom log to use with gsource from build info of sp/fn of db Parameters @opt options util script only utility or sp/fn with __ in the name run produce the log Notes After that you can save the output to a file and call gource: gource.exe --log-format svn -s 0.1 --stop-at-end --max-file-lag 10 --title "myTitle" -640x480 --hide bloom,progress,dirnames --disable-auto-rotate --key --file-idle-time 0 --camera-mode overview -o output.ppm output.log ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i output.ppm -vcodec libx264 -preset ultrafast -crf 1 -threads 0 -bf 0 output.avi '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__util_gource' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_gource: -- ========================================================== sp__util_instances select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_instances',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120112 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_instances') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_instances') with nowait goto skip_sp__util_instances end if @ver>120112 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_instances') with nowait goto skip_sp__util_instances end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_instances') with nowait if exists( select top 1 null from sys.objects where name='sp__util_instances' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_instances] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120112\s.zaglio: list infor about running instances c: originally from: http://social.msdn.microsoft.com/Forums/en/ sqlsetupandupgrade/thread/fe689d83-0264-45d7-8d73-5b1ac43d09a6 */ create proc sp__util_instances @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interfering with select statements. set nocount on -- if @dbg>=@@nestlevel exec sp__printf ''write here the error msg'' declare @proc sysname, @err int, @ret int -- standard API: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == Declare @CurrID int,@ExistValue int, @MaxID int, @SQL nvarchar(1000) Declare @TCPPorts Table (PortType nvarchar(180), Port int) Declare @SQLInstances Table (InstanceID int identity(1, 1) not null primary key, InstName nvarchar(180), Folder nvarchar(50), StaticPort int null, DynamicPort int null, Platform int null); Declare @Plat Table (Id int,Name varchar(180),InternalValue varchar(50), Charactervalue varchar (50)) Declare @Platform varchar(100) Insert into @Plat exec xp_msver platform select @Platform = (select 1 from @plat where charactervalue like ''%86%'') If @Platform is NULL Begin Insert Into @SQLInstances (InstName, Folder) Exec xp_regenumvalues N''HKEY_LOCAL_MACHINE'', N''SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL''; Update @SQLInstances set Platform=64 End else Begin Insert Into @SQLInstances (InstName, Folder) Exec xp_regenumvalues N''HKEY_LOCAL_MACHINE'', N''SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL''; Update @SQLInstances Set Platform=32 End Declare @Keyexist Table (Keyexist int) Insert into @Keyexist Exec xp_regread''HKEY_LOCAL_MACHINE'', N''SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\Instance Names\SQL''; select @ExistValue= Keyexist from @Keyexist If @ExistValue=1 Insert Into @SQLInstances (InstName, Folder) Exec xp_regenumvalues N''HKEY_LOCAL_MACHINE'', N''SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\Instance Names\SQL''; Update @SQLInstances Set Platform =32 where Platform is NULL Select @MaxID = MAX(InstanceID), @CurrID = 1 From @SQLInstances While @CurrID <= @MaxID Begin Delete From @TCPPorts Select @SQL = ''Exec xp_instance_regread N''''HKEY_LOCAL_MACHINE'''', N''''SOFTWARE\Microsoft\\Microsoft SQL Server\'' + Folder + ''\MSSQLServer\SuperSocketNetLib\Tcp\IPAll'''', N''''TCPDynamicPorts'''''' From @SQLInstances Where InstanceID = @CurrID Insert Into @TCPPorts Exec sp_executesql @SQL Select @SQL = ''Exec xp_instance_regread N''''HKEY_LOCAL_MACHINE'''', N''''SOFTWARE\Microsoft\\Microsoft SQL Server\'' + Folder + ''\MSSQLServer\SuperSocketNetLib\Tcp\IPAll'''', N''''TCPPort'''''' From @SQLInstances Where InstanceID = @CurrID Insert Into @TCPPorts Exec sp_executesql @SQL Select @SQL = ''Exec xp_instance_regread N''''HKEY_LOCAL_MACHINE'''', N''''SOFTWARE\Wow6432Node\Microsoft\\Microsoft SQL Server\'' + Folder + ''\MSSQLServer\SuperSocketNetLib\Tcp\IPAll'''', N''''TCPDynamicPorts'''''' From @SQLInstances Where InstanceID = @CurrID Insert Into @TCPPorts Exec sp_executesql @SQL Select @SQL = ''Exec xp_instance_regread N''''HKEY_LOCAL_MACHINE'''', N''''SOFTWARE\Wow6432Node\Microsoft\\Microsoft SQL Server\'' + Folder + ''\MSSQLServer\SuperSocketNetLib\Tcp\IPAll'''', N''''TCPPort'''''' From @SQLInstances Where InstanceID = @CurrID Insert Into @TCPPorts Exec sp_executesql @SQL Update SI Set StaticPort = P.Port, DynamicPort = DP.Port From @SQLInstances SI Inner Join @TCPPorts DP On DP.PortType = ''TCPDynamicPorts'' Inner Join @TCPPorts P On P.PortType = ''TCPPort'' Where InstanceID = @CurrID; Set @CurrID = @CurrID + 1 End Select serverproperty(''ComputerNamePhysicalNetBIOS'') as ServerName, InstName, StaticPort, DynamicPort,Platform From @SQLInstances -- goto ret -- =================================================================== errors == -- err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope list info about running instances Parameters Examples '' -- select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc SP__UTIL_INSTANCES' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_instances: -- ========================================================== sp__util_normalize select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_normalize',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120904 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_normalize') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_normalize') with nowait goto skip_sp__util_normalize end if @ver>120904 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_normalize') with nowait goto skip_sp__util_normalize end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_normalize') with nowait if exists( select top 1 null from sys.objects where name='sp__util_normalize' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_normalize] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:table,normalize,view TODO:create at least clustered index r:120904\s.zaglio: added distinct of distinct r:120829\s.zaglio: normalize a table creating a dictionary t:sp__util_normalize ''rep05_delivery_notes'',@opt=''overwrite'',@dbg=1 t:exec sp__info_db ''rep05_delivery_notes%'' t:select top 10 * from REP05_DELIVERY_NOTES_NORM */ CREATE proc sp__util_normalize @tbl sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @tbl is null and @opt=''||'' goto help -- ============================================================== declaration == declare @sql nvarchar(max), -- final sql to execute @flds nvarchar(max), -- fields list @from nvarchar(max), -- from clause @pk nvarchar(4000), -- pkey cols @tmp nvarchar(max), @id int,@i int,@n int,@top int, @qtbl sysname, -- quoted table name @ntbl sysname, -- normalized name @dict sysname, @dict_ix sysname, -- dictionary tbl&idx @qdict sysname, @qnorm sysname, -- quoted normalized table name @qview sysname, -- quoted name view -- options @overwrite bit, -------- @crlf nvarchar(2), @end_declare bit create table #pk( id int identity, k1 sql_variant,k2 sql_variant null, k3 sql_variant null, k4 sql_variant null, grp int null, ) create index #ix_pk on #pk(grp) -- =========================================================== initialization == select @id=object_id(@tbl) select @tbl=name from sys.objects where object_id=@id -- real name select @ntbl=@tbl, @qtbl=quotename(@tbl), @dict=@ntbl+''_DICT'', @dict_ix=''IX_''+@ntbl+''_DICT'', @qdict=quotename(@dict), @qnorm=quotename(@ntbl+''_NORM''), @qview=quotename(@ntbl+''_ALL''), -- options @overwrite=charindex(''|overwrite|'',@opt), -------- @crlf=crlf, -------- @end_declare=1 from fn__sym() -- ======================================================== second params chk == if not exists( select top 1 * from sys.objects where object_id=@id and [type]=''U'' ) goto err_tbl -- ===================================================================== body == -- collect %varchar columns select distinct c.name, right(''0000''+cast(c.column_id as sysname),4) cid, t.name as [type] into #cols -- select top 10 * from sys.columns c join sys.types t on c.system_type_id=t.user_type_id where object_id=@id -- select * from sys.types order by system_type_id if @dbg>1 select * from #cols order by cid -- ================================================================ get pkeys == select @top=dbo.fn__count(@tbl),@n=@top/65536 exec sp__printf ''-- %d records in %d chunks'',@i,@n /* select @pk=null,@i=1 select @pk=isnull(@pk+'','','''')+quotename(columnname), @tmp=isnull(@tmp+'','','''')+''K''+cast(@i as varchar), @i=@i+1 from fn__script_idx(@id) where [primary]=1 select @sql=''insert #pk(''+@tmp+'') select ''+@pk+'' from ''+@qtbl if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) update #pk set grp=id%65536 */ -- goto master_tbl -- ================================================== create dictionary table == -- drop view before because schemabind if not object_id(@qview) is null exec(''drop view ''+@qview) if not object_id(@dict) is null begin if @overwrite=1 exec(''drop table ''+@qdict) else goto err_exs end select @sql=''create table ''+@qdict+''(id int identity ''+ ''constraint [PK''+@ntbl+''] primary key,txt nvarchar(4000))'' if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) select @sql=''create /*unique*/ index [''+@dict_ix+''] on ''+@qdict+''(txt)'' if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) -- for each varchar col, fill dictionary select @sql=null select @sql=isnull(@sql+'' union''+@crlf,'''')+ +''select distinct [''+c.name+''] from ''+@qtbl +'' where not [''+c.name+''] is null'' from #cols c where c.[type] like ''%varchar'' select @sql=''insert ''+@qdict+@crlf+@sql+@crlf if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) if @@error!=0 goto err_cod -- ======================================================== fill master table == master_tbl: if not object_id(@qnorm) is null exec(''drop table ''+@qnorm) -- select fld,d1.col_id as col_id,... from tbl join dict d1 select @flds=null select @flds=isnull(@flds+'',''+@crlf,'''') +case when c.[type] like ''%varchar'' then '' D''+cid+''.ID as [''+c.name+''_DID]'' else '' TBL.''+c.name end from #cols c order by c.cid select @from=''from ''+@qtbl+'' TBL with(nolock)''+@crlf select @from=@from +''left join '' -- left because can be null value +@qdict+'' as D''+cid+'' with (nolock) '' +'' on TBL.''+c.name+''=D''+cid+''.txt''+@crlf from #cols c where c.[type] like ''%varchar'' order by c.cid -- create select @sql=''select top 0''+@crlf+@flds+@crlf+''into ''+@qnorm+@crlf+@from if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) -- insert select @sql =''insert ''+@qnorm+@crlf +''select top ''+cast(@top as sysname)+@crlf -- prevent bad joins +@flds+@crlf+@from if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) -- ============================================================== create view == create_view: -- hints and left join prevent create of indexes on view select @from=''from dbo.''+@qnorm+'' TBL ''+@crlf select @from=@from +''left join '' -- left because can be null value +''dbo.''+@qdict+'' as D''+cid +'' on TBL.''+c.name+''_DID=D''+cid+''.id''+@crlf from #cols c where c.[type] like ''%varchar'' order by c.cid select @flds=null select @flds=isnull(@flds+'',''+@crlf,'''') +case when c.[type] like ''%varchar'' then '' D''+cid+''.TXT as [''+c.name+'']'' else '' TBL.''+c.name end from #cols c -- where not c.type like ''%text'' -- do not allow -- and not c.type like ''%image'' -- clustered index order by c.cid select @sql =''create view ''+@qview+@crlf +''with schemabinding''+@crlf +''as''+@crlf +''select''+@crlf +@flds+@crlf +@from+@crlf if @sql is null goto err_cod if @dbg=1 exec sp__printsql @sql exec(@sql) -- ================================================================ add index == add_index: goto ret -- =================================================================== errors == err_tbl: exec @ret=sp__err ''table not found or not a table'',@proc goto ret err_exs: exec @ret=sp__err ''destination exists; use OVERWRITE option'',@proc goto ret err_cod: exec @ret=sp__err ''inside sql code error'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope normalize a table creating a @tbl_DICT that contain all varchars and a @tbl_NORM that containt linked data and a @tbl_ALL that is a view that join NORM with DICT. Parameters @tbl is the name of table to normalize @opt options overwrite overwrite dict tables if exists Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__util_normalize' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_normalize: -- ================================================================= sp__util_os select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_os',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120208 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_os') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_os') with nowait goto skip_sp__util_os end if @ver>120208 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_os') with nowait goto skip_sp__util_os end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_os') with nowait if exists( select top 1 null from sys.objects where name='sp__util_os' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_os] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:120208\s.zaglio: added code comment v:120126\s.zaglio: used cscript v:110125\s.zaglio: exp buf of cmdline to 256 instead of 128 v:100919.1110\s.zaglio: a remake because outof return space (4000chars limit) v:100919.1100\s.zaglio: more info about processes v:100119\s.zaglio: int->bigint v:100105\s.zaglio: list windows processes t:sp__util_os list */ CREATE proc [dbo].[sp__util_os] @cmd sysname=null, @opt sysname=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 -- if @dbg=1 select *,dbo.fn__str_at(@cmd,'''',pos) at from fn__str_table(@cmd,'''') if @cmd is null or not dbo.fn__str_at(@cmd,'''',1) in (''kill'',''list'') goto help select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') declare @list table (pos int,token nvarchar(4000)) declare @i int,@n int,@line nvarchar(4000), @vbs nvarchar(4000),@sql nvarchar(4000), @tmp nvarchar(4000),@pid bigint, @csep nchar(1),@rsep nchar(1), @out bit, @p1 sysname declare @stdout table (lno int identity,line nvarchar(4000)) create table #src(lno int identity,line nvarchar(4000)) create table #tpl(lno int identity primary key,line nvarchar(4000)) select @p1=isnull(dbo.fn__str_at(@cmd,'''',2),''''), @cmd=dbo.fn__str_at(@cmd,'''',1) if @dbg=1 exec sp__printf ''cmd=%s p1=%s'',@cmd,@p1 select @csep=''|'',@rsep=char(13) if object_id(''tempdb..#osprocs'') is null begin create table #osprocs ( pid bigint, [name] sysname, kb bigint, nWrites bigint, KTime bigint, UTime bigint, CmdLine nvarchar(1024) ) select @out=1 end else select @out=0 /* In alternative can use the WMIC utility WMIC PROCESS get Caption,Commandline,Processid /Format:list WMIC PROCESS where name="cmd.exe" get processid,commandline /format:list WMIC PROCESS where processid=??? delete */ insert #tpl(line) select line from fn__ntext_to_lines('' %kill%: sub KillProcessTree(objWMIService,process) ''''wscript.echo process.name, process.handle, ''''"is a child of",process.parentprocessid wql = "select * from win32_process " & _ "where ParentProcessID=" & process.handle set results = objWMIService.execquery(wql) for each childProcess in results KillProcessTree objWMIService,childProcess next process.terminate end sub strComputer = "." strConn="winmgmts:" ''''strConn= _ '''' "winmgmts:" & _ '''' "{impersonationLevel=impersonate,(debug)}!\\" & _ '''' strComputer & "oot\cimv2" _ Set objWMIService = GetObject( strConn ) Set colProcessList = objWMIService.ExecQuery _ ("Select * from Win32_Process Where handle = %pid%") For Each objProcess in colProcessList set rootProcess = objWMIService.get( _ "win32_process.handle=" & objProcess.Handle _ ) KillProcessTree objWMIService,rootProcess Next -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- %list%: Dim obj, obj1 , row , sql, cmdl sql="SELECT " & _ "name,WorkingSetSize,WriteOperationCount," & _ "KernelModeTime,UserModeTime,CommandLine " & _ "FROM Win32_Process " & _ "WHERE name like ''''%name%%''''" For Each obj In GetObject("winmgmts:").ExecQuery(sql) row = obj.handle & "|" & _ obj.name & "|" & _ obj.WorkingSetSize & "|" & _ obj.WriteOperationCount & "|" & _ obj.KernelModeTime & "|" & _ obj.UserModeTime cmdl = obj.handle & "|" & obj.CommandLine Wscript.StdOut.WriteLine row Wscript.StdOut.WriteLine cmdl Next -- -- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- --8<-- -- -- -- -- -- '',0) if @cmd=''list'' -- sp__util_os ''list cmd'' -- sp__util_os list exec sp__script_template ''%list%'',@opt=''mix'',@tokens=''%name%'',@v1=@p1 if @cmd=''kill'' begin -- sp__util_os ''kill 4984'',@dbg=1 if isnumeric(@p1)=1 exec sp__script_template ''%kill%'',@opt=''mix'', @tokens=''%pid%'',@v1=@p1 else goto err_pid end -- kill if @dbg=1 select * from #src select @vbs=''%temp%\''+replace(cast(newid() as sysname),''-'',''_'')+''.vbs'', @line=''cscript //T:60 //Nologo ''+@vbs -- @line=''cscript ''+@vbs exec sp__file_write_stream @vbs,@fmt=''ascii'' insert @stdout exec xp_cmdshell @line select @line=''del ''+@vbs exec xp_cmdshell @line,no_output select @line=null select top 1 @line=line from @stdout where line like ''%''+@vbs+''(%,%)%'' if not @line is null goto err_vbs if @cmd=''kill'' goto ret if @dbg=1 select * from @stdout o cross apply fn__str_words(o.line,''|'',default) where o.lno%2=1 -- out objects cols order is different from select insert #osprocs(pid,name,kb,nwrites,ktime,utime) select convert(bigint,c00) as pid, convert(sysname,c01) as name, convert(bigint,c02)/1024 as kb, convert(bigint,c03) as nwrites, convert(bigint,c04) as ktime, convert(bigint,c05) as utime from @stdout o cross apply fn__str_words(o.line,''|'',default) where o.lno%2=1 -- update with 2nd line : pid|cmdline update p set cmdline=substring(o.line,charindex(''|'',o.line)+1,1024) from #osprocs p join @stdout o on p.pid=left(o.line,charindex(''|'',o.line)-1) where o.lno%2=0 if @out=1 begin select * from #osprocs where [name] like isnull(dbo.fn__str_at(@cmd,'''',2)+''%'',''%'') drop table #osprocs end else delete from #osprocs where not [name] like isnull(dbo.fn__str_at(@cmd,'''',2)+''%'',''%'') goto ret -- =================================================================== errors == err_vbs: exec @ret=sp__err ''%s'',@proc,@p1=@line goto ret err_pid: exec @ret=sp__err ''not numeric PID'',@proc goto ret /* class Win32_Process : CIM_Process { string Caption; string CommandLine; string CreationClassName; datetime CreationDate; string CSCreationClassName; string CSName; string Description; string ExecutablePath; uint16 ExecutionState; string Handle; uint32 HandleCount; datetime InstallDate; uint64 KernelModeTime; uint32 MaximumWorkingSetSize; uint32 MinimumWorkingSetSize; string Name; string OSCreationClassName; string OSName; uint64 OtherOperationCount; uint64 OtherTransferCount; uint32 PageFaults; uint32 PageFileUsage; uint32 ParentProcessId; uint32 PeakPageFileUsage; uint64 PeakVirtualSize; uint32 PeakWorkingSetSize; uint32 Priority; uint64 PrivatePageCount; uint32 ProcessId; uint32 QuotaNonPagedPoolUsage; uint32 QuotaPagedPoolUsage; uint32 QuotaPeakNonPagedPoolUsage; uint32 QuotaPeakPagedPoolUsage; uint64 ReadOperationCount; uint64 ReadTransferCount; uint32 SessionId; string Status; datetime TerminationDate; uint32 ThreadCount; uint64 UserModeTime; uint64 VirtualSize; string WindowsVersion; uint64 WorkingSetSize; uint64 WriteOperationCount; uint64 WriteTransferCount; }; */ help: exec sp__usage @proc,'' Scope List OS processes Parameters @cmd commands and parameters kill PID list [process] list processes if exists #osprocs, return in this table the processes info create table #osprocs ( pid bigint,[name] sysname, kb bigint, nWrites bigint, KTime bigint, UTime bigint, CmdLine nvarchar(1024) ) Examples sp__util_os list smss '' select @ret=-1 ret: return @ret end -- sp__util_os' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_os: -- ============================================================== sp__util_os_ps select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_os_ps',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=131209 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_os_ps') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_os_ps') with nowait goto skip_sp__util_os_ps end if @ver>131209 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_os_ps') with nowait goto skip_sp__util_os_ps end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_os_ps') with nowait if exists( select top 1 null from sys.objects where name='sp__util_os_ps' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_os_ps] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:process,status,list v:131209\s.zaglio: list os processes using wmi t:sp__util_os_ps ''%'',@dbg=1 */ CREATE proc sp__util_os_ps @name sysname = null, @opt sysname = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly -- @@nestlevel is >1 if called by other sp (not correct if called by remote sp) set nocount on declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id @err_msg nvarchar(2000) -- used before raise -- ======================================================== params set/adjust == select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=nullif(@opt,''''), @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- @param=nullif(@param,''''), -- ============================================================== declaration == declare @tmp nvarchar(512), @cmd nvarchar(4000), @txt nvarchar(max), @sql nvarchar(max), @cols sysname, @i int, @crlf nvarchar(2), @osprocs_id int -- =========================================================== initialization == exec sp__get_temp_dir @tmp out,@opt=''tf'' select @tmp=@tmp+''.txt'', @crlf=crlf, @osprocs_id=isnull(object_id(''tempdb..#osprocs''),0) from fn__sym() -- ======================================================== second params chk == if @name is null goto help -- =============================================================== #tbls init == declare @src table(lno int identity primary key,line nvarchar(4000)) declare @osprocs table( pid bigint, [name] sysname null, kb bigint null, nWrites bigint null, KTime bigint null, UTime bigint null, CmdLine nvarchar(1024) null ) -- ===================================================================== body == -- http://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx -- get * or nothing for all -- the list output follow the alphabetic order select @cols=''Caption,Handle,CommandLine,Name,KernelModeTime,UserModeTime,'' +''WorkingSetSize,WriteOperationCount'' select @cmd=''wmic /output:"''+@tmp+''" process get ''+@cols+'' /format:value'' if @dbg=0 exec xp_cmdshell @cmd,no_output else begin exec sp__printf ''%s'',@cmd exec xp_cmdshell @cmd end select @sql=''select @txt=BulkColumn '' +''from openrowset(bulk ''''''+@tmp+'''''', single_nclob) as x'' if @dbg>0 exec sp__printsql @sql exec sp_executesql @sql,N''@txt nvarchar(max) out'',@txt=@txt out if @dbg>0 exec sp__printsql @txt select @cmd=''del /f /q "''+@tmp+''"'' exec xp_cmdshell @cmd,no_output insert @src(line) select line from fn__ntext_to_lines(@txt,0) -- t:sp__util_os_ps ''%'',@dbg=1 ;with var_val as ( select lno, left(line,charindex(''='',line)-1) as [var], substring(line,charindex(''='',line)+1,len(line)) as [val] from @src where line!='''' ), hdr as ( select row_number() over(partition by 1 order by lno) as row,* from var_val where [var]=''caption'' ), maxlno as ( select max(lno) as mlno from @src ), range as ( select row_number() over(partition by 1 order by (select 1)) as gid, h1.lno llno,isnull(h2.lno-1,mlno) rlno from maxlno,hdr h1 left join hdr h2 on h1.row+1=h2.row ), vals as ( select b.gid,a.* from var_val a join range b on a.lno between b.llno and b.rlno ), Handle as ( select gid,val as handle from vals where [var]=''handle'' ), Name as ( select gid,val as Name from vals where [var]=''name'' ), CommandLine as ( select gid,left(val,1024) as CommandLine from vals where [var]=''CommandLine'' ), KernelModeTime as ( select gid,val as KernelModeTime from vals where [var]=''KernelModeTime'' ), UserModeTime as ( select gid,val as UserModeTime from vals where [var]=''UserModeTime'' ), WorkingSetSize as ( select gid,val as WorkingSetSize from vals where [var]=''WorkingSetSize'' ), WriteOperationCount as ( select gid,val as WriteOperationCount from vals where [var]=''WriteOperationCount'' ) insert @osprocs( pid,name,cmdline, KTime,UTime, kb,nWrites ) select handle,name,commandline, KernelModeTime,UserModeTime, WorkingSetSize,WriteOperationCount from handle join name on handle.gid=name.gid join commandline on handle.gid=commandline.gid join KernelModeTime on handle.gid=KernelModeTime.gid join UserModeTime on handle.gid=UserModeTime.gid join WorkingSetSize on handle.gid=WorkingSetSize.gid join WriteOperationCount on handle.gid=WriteOperationCount.gid where name like @name if @osprocs_id=0 select * from @osprocs else insert #osprocs select * from @osprocs -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope List OS processes with info. Notes - called by sp__util_os - maybe compatible with all present and future version of Windows starting from XP (probably SP 3 and above) Parameters [param] [desc] @name like expression over name #osprocs returned table if exists create table #osprocs ( pid bigint,[name] sysname, kb bigint, nWrites bigint, KTime bigint, UTime bigint, CmdLine nvarchar(1024) ) @opt options @dbg 1=last most importanti info/show code without execute it 2=more up level details 3=more up ... Examples sp__util_os_ps "%" '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch -- if @@trancount > 0 rollback -- for nested trans see style "procwnt" exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__util_os_ps' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_os_ps: -- ========================================================== sp__util_sp2dotnet select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_sp2dotnet',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110326 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_sp2dotnet') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_sp2dotnet') with nowait goto skip_sp__util_sp2dotnet end if @ver>110326 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_sp2dotnet') with nowait goto skip_sp__util_sp2dotnet end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_sp2dotnet') with nowait if exists( select top 1 null from sys.objects where name='sp__util_sp2dotnet' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_sp2dotnet] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g: script,utility v:110326\s.zaglio: added parameters clear v:110305\s.zaglio: done first version r:100127\s.zaglio: create a vb function to call a sp t:sp__util_sp2dotnet ''sp__util_sp2dotnet'',@opt=''class'' */ CREATE proc [dbo].[sp__util_sp2dotnet] @obj sysname=null, @base sysname=null out, @lng sysname=null, @opt sysname=null, @dbg int=null as begin set nocount on declare @proc sysname,@ret int,@err int select @proc=object_name(@@procid),@ret=0,@dbg=isnull(@dbg,0) select @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @obj is null and object_id(''tempdb..#objs'') is null goto help select @lng=isnull(@lng,''vbnet''), @base=isnull(@base,''db'') if not @lng in (''vbnet'') goto help -- ============================================================= declarations == declare @xtype nvarchar(2),@tab1 sysname,@tab2 sysname,@tab3 sysname,@id int if object_id(''tempdb..#objs'') is null create table #objs(obj sysname,xtype nvarchar(2) null) create table #src(lno int,line nvarchar(4000)) create table #cols( id int identity, col sysname, xtype sysname, ln sysname,prec sysname,scale sysname, nullable bit,isout bit, vbtype sysname null ) -- =========================================================== initialization == select @tab1='' '',@tab2=@tab1+@tab1,@tab3=@tab2+@tab1 if not @obj is null insert #objs(obj,xtype) select [name],xtype from sysobjects where [name] like @obj -- ===================================================================== body == -- add header if charindex(''|class|'',@opt)>0 begin insert into #src(line) select '''''' v:''+convert(sysname,getdate(),12)+''.'' +left(replace(convert(sysname,getdate(),8),'':'',''''),4) +''\sp__util_sp2dotnet: generated automatically'' insert into #src(line) select ''Imports System'' insert into #src(line) select ''Imports System.Data'' insert into #src(line) select '''' insert into #src(line) select ''Public Class ''+@base+''_objs'' insert into #src(line) select @tab1+''Inherits ''+@base insert into #src(line) select '''''' inherited by ''+@base+''_io'' insert into #src(line) select '''' insert into #src(line) select @tab1+''Public Sub New(Optional ByVal cs As String = "")'' insert into #src(line) select @tab2+''MyBase.New(cs)'' insert into #src(line) select @tab1+''End Sub'' insert into #src(line) select '''' end -- class -- add stored declare cs cursor local for select obj,xtype,object_id(obj) from #objs where 1=1 open cs while 1=1 begin fetch next from cs into @obj,@xtype,@id if @@fetch_status!=0 break if @xtype!=''P'' begin exec sp__printf ''%s excluded because not managed type(%s)'',@obj,@xtype continue end truncate table #cols insert #cols(col,xtype,ln,prec,scale,nullable,isout,vbtype) -- declare @id int select @id=object_id(''swl_rfc'') select -- select * from systypes c.[name],case when t.xusertype=256 then ''nvarchar'' else t.[name] end , case -- select * from systypes when c.xusertype in (175,239,231,167,256) --char,nchar,nvc,vc then c.prec else c.length end as [length], case -- select * from systypes when c.xusertype in (175,239,231,167,256) --char,nchar,nvc,vc then 0 else c.prec end as prec, isnull(convert(sysname,c.scale),''nothing'') as scale, c.isnullable,c.isoutparam, case -- select * from systypes when c.xusertype in (175,239,231,167,256) --char,nchar,nvc,vc then ''string'' -- +''(''+convert(sysname,prec)+'')'' when c.xusertype in (62,106,108) then ''double'' -- float,decimal,numeric when c.xusertype in (59) then ''single'' -- real when c.xusertype in (61,58) then ''date'' -- *datetime when c.xusertype in (56) then ''int32'' -- int when c.xusertype in (52) then ''int16'' -- smallint when c.xusertype in (48) then ''byte'' -- tinyint when c.xusertype in (60) then ''currency'' -- money when c.xusertype in (35,99) then ''string'' -- text,ntext when c.xusertype in (104) then ''boolean'' -- bit when c.xusertype in (98) then ''object'' -- sql_variant else ''object ''''unk type'' end as vbtype from syscolumns c join systypes t on c.xusertype=t.xusertype where c.id=@id order by colid insert into #src(line) select @tab1+''public function [''+@obj+'']( _'' insert into #src(line) -- select * from systypes -- select * from syscolumns c where id=object_id('''') select @tab3+ case when nullable =1 then ''optional '' else '''' end+ case isout when 1 then ''byref '' else ''byval '' end+ substring(col,2,4000)+'' as ''+ vbtype+ case when nullable=1 then ''=nothing'' else '''' end+ '', _'' from #cols order by id insert into #src(line) select @tab3+''optional byref raiserrorIfRetNotIs as integer=0, _'' insert into #src(line) select @tab3+''optional byval tst_params as boolean=false _'' insert into #src(line) select @tab2+'') as dataset'' insert into #src(line) select '''' insert into #src(line) select @tab1+''Dim ex As Exception = Nothing'' insert into #src(line) select @tab1+''Dim retval as integer,da as SqlClient.SqlDataAdapter=nothing'' insert into #src(line) select @tab1+''Dim ds as system.Data.DataSet=nothing'' insert into #src(line) select @tab1+''Dim p As system.Data.SqlClient.SqlParameter'' insert into #src(line) select '''' insert into #src(line) select @tab1+''p=New system.Data.SqlClient.SqlParameter("retvalue", SqlDbType.Int)'' insert into #src(line) select @tab1+''p.Direction = ParameterDirection.ReturnValue'' insert into #src(line) select @tab1+''cmd.Parameters.Clear()'' insert into #src(line) select @tab1+''cmd.parameters.add(p)'' insert into #src(line) select top 100 percent ''cmd.parameters.add(New system.Data.SqlClient.SqlParameter(''+ ''"''+col+''",SqlDbType.''+xtype+'',''+ ln+'',''+ case when isout=1 then ''ParameterDirection.InputOutput'' else ''ParameterDirection.Input'' end+'',''+ case when nullable=1 then ''true,'' else ''false,'' end+ prec+'',''+ scale+'',''+ ''nothing,DataRowVersion.Current,''+ substring(col,2,4000) +''))'' as line from #cols order by id insert into #src(line) select @tab1+''cmd.CommandType = System.Data.CommandType.StoredProcedure'' insert into #src(line) select @tab1+''cmd.CommandText="''+@obj+''"'' insert into #src(line) select @tab1+''debug(cmd)'' -- .Parameters("au_id").Value = "172-32-1176" insert into #src(line) select @tab1+''da = New SqlClient.SqlDataAdapter(cmd)'' insert into #src(line) select @tab1+''ds = New system.Data.DataSet'' insert into #src(line) select @tab1+''timer.Start()'' insert into #src(line) select @tab1+''try'' insert into #src(line) select @tab1+''da.Fill(ds)'' insert into #src(line) select @tab1+''catch local_ex As Exception'' insert into #src(line) select @tab3+''ex=local_ex'' insert into #src(line) select @tab1+''end try'' insert into #src(line) select @tab1+''cmd.CommandType = System.Data.CommandType.Text'' insert into #src(line) select @tab1+''timer.Stop()'' insert into #src(line) select @tab1+''da.Dispose()'' insert into #src(line) select @tab1+''da = Nothing'' insert into #src(line) select @tab3+''if not ex is nothing then throw ex'' insert into #src(line) select @tab1+''retval=nz(CType(cmd.Parameters("retvalue").Value, Integer),0)'' insert into #src(line) select @tab1+''if retval<>raiserrorIfRetNotIs then'' insert into #src(line) select @tab3+''throw new exception("error(" & retval & ") in ""'' + @obj + ''""")'' insert into #src(line) select @tab1+''else'' insert into #src(line) select @tab3+''raiserrorIfRetNotIs = retval'' insert into #src(line) select @tab1+''end if '' -- output values insert into #src(line) select top 100 percent @tab1+substring(col,2,4000)+''=CType(cmd.Parameters("''+col+''").Value, ''+vbtype+'')'' as line from #cols where isout=1 order by id insert into #src(line) select @tab1+''return ds'' insert into #src(line) select @tab1+''end function '''' ''+@obj end -- while of cursor close cs deallocate cs if charindex(''|class|'',@opt)>0 begin insert into #src(line) select '''' insert into #src(line) select ''End Class '''' ''+@base+''_objs'' end -- class select line from #src order by lno drop table #src drop table #cols goto ret -- =================================================================== errors == -- ===================================================================== help == help: exec sp__usage @proc,'' Scope generate the dotnet code necessary to use the objects of db Parameters @obj object name, can use wild % can pass directly #objs as create table #objs(obj sysname,xtype nvarchar(2) null) @base is the base class used with "class" option; by default is "db" @lng specify .net language of output possible languages are: null (default) vbnet (default) @opt options class enclose functions into class db_io inherited from db svn TODO:out to svn (see sp__svn) '' ret: return @ret end -- [sp__util_sp2dotnet]' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_sp2dotnet: -- ========================================================== sp__util_sqlrecent select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_sqlrecent',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120731.1000 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_sqlrecent') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_sqlrecent') with nowait goto skip_sp__util_sqlrecent end if @ver>120731.1000 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_sqlrecent') with nowait goto skip_sp__util_sqlrecent end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_sqlrecent') with nowait if exists( select top 1 null from sys.objects where name='sp__util_sqlrecent' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_sqlrecent] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:perf,sql r:120731.1000\s.zaglio: show recent query */ CREATE proc sp__util_sqlrecent @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- if @opt=''||'' goto help -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == select distinct db_name(dbid) db, object_name(objectid,dbid) obj, deqs.last_execution_time as [time], last_worker_time,min_worker_time,max_worker_time, dest.text as [query] -- ,substring(dest.text,statement_start_offset,case statement_end_offset when -1 then len(dest.text) else statement_end_offset end) stmnt -- ,* from sys.dm_exec_query_stats as deqs cross apply sys.dm_exec_sql_text(deqs.sql_handle) as dest order by deqs.last_execution_time desc goto help goto ret -- =================================================================== errors == /* err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope list lrecent queryes with times Parameters [param] [desc] Examples [example] '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__util_sqlrecent' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_sqlrecent: -- ============================================================= sp__util_status select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_status',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100328 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_status') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_status') with nowait goto skip_sp__util_status end if @ver>100328 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_status') with nowait goto skip_sp__util_status end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_status') with nowait if exists( select top 1 null from sys.objects where name='sp__util_status' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_status] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:100328\s.zaglio: added help v:100212\s.zaglio: added drives free space inspect v:100131\s.zaglio: save and compare mssql configuration t:sp__util_status @reset=1,@dbg=1 t: declare @r int exec @r=[sp__util_status] @dbg=1 print @r select * from TBL_SAVED_CONFIGURATION where tid=''dri'' */ CREATE proc [dbo].[sp__util_status] @reset bit=0, @dbg bit=0 as begin set nocount on declare @proc sysname,@sql nvarchar(4000),@dt datetime,@i int,@n int,@j int,@r int declare @first datetime,@last datetime select @proc=''sp__util_status'', @dt=getdate(), @r=1 -- drop table TBL_SAVED_CONFIGURATION if dbo.fn__exists(''TBL_SAVED_CONFIGURATION'',''u'')=0 begin -- declare @proc sysname,@sql nvarchar(4000),@dt datetime,@i int,@n int select @sql=''create table TBL_SAVED_CONFIGURATION (\n'' +''\ttid char(4),\n\thdr bit default 0,id int identity,\n\tdt datetime'' select @i=1,@n=30 while @i<=@n select @sql=@sql+'',\n\tv''+convert(sysname,@i)+'' sysname null'',@i=@i+1 select @sql=@sql+'')'' select @sql=replace(@sql,''\n'',char(13)) select @sql=replace(@sql,''\t'','' '') exec sp__printf ''-- creating table '' exec(@sql) select @reset=1 end -- delete last registration select @first=min(dt),@last=max(dt) from TBL_SAVED_CONFIGURATION if @first!=@last delete from TBL_SAVED_CONFIGURATION where dt=@last create table #sp_configure ( name sysname, minimum int, maximum int, config_value int, run_value int) insert into #sp_configure exec sp_configure -- select * from #sp_configure select * into #databases from master..sysdatabases with (nolock) select * into #servers from master..sysservers with (nolock) create table #drives(name sysname,freeperc int) exec sp__util_drives ''letter,pc'',''#drives'',@dbg=1 if @reset=1 begin exec sp__printf ''-- 1st registration'' truncate table TBL_SAVED_CONFIGURATION end -- declare @j int,@i int,@n int,@sql nvarchar(4000),@dt datetime select @dt=getdate() declare @flds nvarchar(4000),@tbls sysname,@tbl sysname,@tid sysname select @tbls=''#sp_configure:cfg,#databases:dbs,#servers:svrs,#drives:dri'' select @j=dbo.fn__str_count(@tbls,'','') while @j>0 begin select @tbl=dbo.fn__str_at(@tbls,'','',@j) select @tid=dbo.fn__str_at(@tbl,'':'',2) select @tbl=dbo.fn__str_at(@tbl,'':'',1),@j=@j-1 exec sp__printf ''-- saving %s'',@tbl select @flds=dbo.fn__flds_of(@tbl,'','',null) if @dbg=1 exec sp__printf ''@tbl=%s, @flds=%s'',@tbl,@flds select @i=1,@n=dbo.fn__str_count(@flds,'','') if @n>30 select @n=30 select @sql=''insert into TBL_SAVED_CONFIGURATION (tid,hdr,dt'' while @i<=@n select @sql=@sql+'',v''+convert(sysname,@i),@i=@i+1 select @sql =@sql+'')\nselect ''''''+@tid+'''''',1,''''''+convert(sysname,@dt,126)+'''''','' +dbo.fn__str_exp(''''''%%'''''',@flds,'','') select @sql=replace(@sql,''\n'',char(13)) if @dbg=1 exec sp__printf @sql exec(@sql) select @i=1,@n=dbo.fn__str_count(@flds,'','') if @n>30 select @n=30 select @sql=''insert into TBL_SAVED_CONFIGURATION (tid,dt'' while @i<=@n select @sql=@sql+'',v''+convert(sysname,@i),@i=@i+1 select @sql =@sql+'')\nselect ''''''+@tid+'''''',''''''+convert(sysname,@dt,126)+'''''','' +dbo.fn__str_exp(''convert(sysname,%%)'',@flds,'','') select @sql=@sql+''from [''+@tbl+'']'' select @sql=replace(@sql,''\n'',char(13)) if @dbg=1 exec sp__printf @sql exec(@sql) end -- while if @reset=0 begin select @first=min(dt),@last=max(dt) from TBL_SAVED_CONFIGURATION select @sql=''select isnull(a.tid,b.tid) tid,isnull(a.v1,b.v1) v1_key'' select @i=2,@n=30 while (@i<=@n) select @sql=@sql+'',a.v''+convert(sysname,@i)+'',b.v''+convert(sysname,@i),@i=@i+1 select @sql=@sql+'' from TBL_SAVED_CONFIGURATION a full outer join TBL_SAVED_CONFIGURATION b on a.tid=b.tid and a.v1=b.v1 where a.dt=''''''+convert(sysname,@first,126)+'''''' and b.dt=''''''+convert(sysname,@last,126)+'''''' and (a.hdr=1'' select @i=2 select @sql=@sql+'' or 1=case when a.tid=''''dri'''' and convert(int,b.v2)<11 then 1 when a.tid!=''''dri'''' and (1=0'' while (@i<=@n) select @sql=@sql+'' or isnull(a.v''+convert(sysname,@i) +'','''''''')!=isnull(b.v''+convert(sysname,@i)+'','''''''')'',@i=@i+1 select @sql=@sql+'') then 1 else 0 end) order by a.id'' if @dbg=1 exec sp__printf @sql select @n=count(*)/2 from TBL_SAVED_CONFIGURATION where hdr=1 exec(@sql) select @i=@@rowcount,@r=@@error if @i!=@n and @r=0 select @r=1 else select @r=0 end -- compare -- select * from TBL_SAVED_CONFIGURATION order by tid,id -- update TBL_SAVED_CONFIGURATION set v2=v2+1 where id=54 drop table #sp_configure drop table #databases drop table #servers drop table #drives exec sp__usage @proc return @r end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_status: -- ========================================================== sp__util_tounicode select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_tounicode',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091018 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_tounicode') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_tounicode') with nowait goto skip_sp__util_tounicode end if @ver>091018 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_tounicode') with nowait goto skip_sp__util_tounicode end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_tounicode') with nowait if exists( select top 1 null from sys.objects where name='sp__util_tounicode' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_tounicode] begin try exec dbo.sp_executesql @statement = N'/* keep this for MS compatibility l:see LICENSE file g:utility v:091018\s.zaglio: mark objs that use datalength and exclusions of utils and temps v:090915\s.zaglio: final tuning r:090914\s.zaglio: some simple bugs r:090911\s.zaglio: drops from together to one to one r:090910\s.zaglio: revision to generate instead of mange directly r:090813.1700\s.zaglio: generate script to trasform the db to unicode t:sp__util_tounicode @skip_code=1 */ CREATE proc [dbo].[sp__util_tounicode] @uid sysname=''sa'', @pwd sysname='''', @skip_code bit=0, @skip_scripts bit=0, @dbg bit=0 as begin set nocount on /* Due use of not logical names we must use this approch: . . begin transaction . drop sp,fn,vi . script upsized to unicode . commit . . drop fkeys . for each table with varchar,char,text . count rows . make a backup . count backup rows . script table . convert to unicode . drop original . recreate unicoded table . disable eventual identity . reinsert data . compare rows and if eq drop temp data . run script dri . . run script fk . . remove old scrips */ -- select distinct xtype from sysobjects -- test per fkey -- sp_fkeys ''am01_us'' -- sp_find ''FK_AM03_MM_FUNC_AM01_US'' -- select * from sysobjects where parent_obj=object_id(''am01_us'') -- select * from sysobjects where parent_obj=object_id(''AM03_MM_FUNC'') -- select * from sysindexes where id=object_id(''am01_us'') -- select * from sysforeignkeys where rkeyid=object_id(''am01_us'') -- select * from sysobjects where id=623341285 -- print object_name(313768175) -->AM03_MM_FUNC -- drop index AM03_MM_FUNC.FK_AM03_MM_FUNC_AM01_US -- test normale -- select * from sysobjects where parent_obj=object_id(''ot04_stock'') -- select * from sysindexes where id=object_id(''ot04_stock'') declare @proc sysname, @i int,@n int,@j int,@step int,@k int, @obj sysname,@new sysname,@msg nvarchar(4000), @sql nvarchar(4000), @flds nvarchar(4000), @xtype nvarchar(2), @oc_tbl smallint, @oc_dri smallint, @oc_trg smallint, @oc_prp smallint, @oc_fk smallint, @cur_db sysname,@cur_srv sysname, @ret int,@crlf nchar(2), @upsize_marker sysname, @timer datetime, @tmp sysname, @file sysname, @cmd nvarchar(512), @parent_obj int select @proc=''sp__util_tounicode'', @oc_tbl=1, -- table with owner and not chk @oc_dri=20, -- pkey,idx and chk @oc_trg=32, -- triggers only @oc_prp=128, -- ex props @oc_fk=1024, -- only fkeys @cur_db=db_name(), @cur_srv=@@servername, @ret=0, @crlf=nchar(13)+nchar(10), @upsize_marker=''-- saved:''+convert(sysname,getdate(),126) exec sp__printf ''-- @cur_db=%s, @spid=%d, @procid=%d'',@cur_db,@@spid,@@procid create table #objs(id int identity(1,1),obj sysname,xtype nvarchar(2),parent_obj int) -- sp,fn,vi declare @xt_vchar int,@xt_char int,@xt_text int select @xt_vchar=xtype from systypes where name=''varchar'' select @xt_char=xtype from systypes where name=''char'' select @xt_text=xtype from systypes where name=''text'' select @step=10 -- temp table create table #src (lno int identity(10,10),line nvarchar(4000)) create table #dri (lno int identity(10,10),line nvarchar(4000)) /* create table @exclude (id int identity,obj sysname) insert into @exclude(obj) select token from dbo.fn__str_table(@excludes,''|'') select @i=min(id),@n=max(id) from @exclude while (@i<=@n) begin select @obj=obj from @exclude where id=@i if charindex(''%'',@ end */ /* exec sp__drop ''tmp_*'',@simul=0 */ exec sp__elapsed @timer out,''-- script generation started at:'' -- select sp,fn,vi that have varchar,char,text -- select top 1 * from sysusers insert into #objs(obj,xtype,parent_obj) select quotename(u.name)+''.''+quotename(o.name),o.xtype,o.parent_obj from sysobjects o join sysusers u on o.uid=u.uid where o.xtype in (''P'',''FN'',''IF'',''TF'',''V'') and (exists( select null from syscolumns c where c.id=o.id and c.xtype in (@xt_vchar,@xt_char,@xt_text) ) or exists( select null from syscomments c where c.id=o.id and ( charindex(''varchar'',[text])=1 or charindex(''char'',[text])=1 or charindex(''text'',[text])=1 or charindex(''[varchar'',[text])>0 or charindex(''[char'',[text])>0 or charindex(''[text'',[text])>0 or charindex('' varchar'',[text])>0 or charindex('' char'',[text])>0 or charindex('' text'',[text])>0 ) ) ) and not ( o.name in (''dtproperties'',@proc) or o.name like ''dt[_]%'' or o.name like ''sys%'' or o.name like ''tmp[_]%'' or o.name like ''[sfv][pni][__]%'' -- sp__,fn__,vi__ or o.name like ''%[_]tmp'' or o.name like ''%[_]temp'' or o.name like ''%[_]tmp'' or o.name like ''%[_]backup'' or o.name like ''%[_]test'' or o.name like ''%[_][0-9][0-9][0-9][0-9][0-9][0-9][_][0-9][0-9][0-9][0-9]'' -- *_AAMMGG_HHMM ) order by xtype,o.name -- select tables that have varchar,char,text -- select * from sysforeignkeys insert into #objs(obj,xtype,parent_obj) select quotename(u.name)+''.''+quotename(o.name),o.xtype,o.parent_obj -- case when o.xtype=''F'' then f.rkeyid else o.parent_obj end from sysobjects o join sysusers u on o.uid=u.uid -- left join sysforeignkeys f -- on o.id=f.constid where o.xtype=''F'' -- foreignkeys or (o.xtype=''U'' and (exists( select null from syscolumns c where c.id=o.id and c.xtype in (@xt_vchar,@xt_char,@xt_text) ) or exists( select null from syscomments c where c.id=o.id and ( charindex(''varchar'',[text])=1 or charindex(''char'',[text])=1 or charindex(''text'',[text])=1 or charindex(''[varchar'',[text])>0 or charindex(''[char'',[text])>0 or charindex(''[text'',[text])>0 or charindex('' varchar'',[text])>0 or charindex('' char'',[text])>0 or charindex('' text'',[text])>0 ) ) ) and not ( o.name in (''dtproperties'',@proc) or o.name like ''dt[_]%'' or o.name like ''sys%'' or o.name like ''tmp[_]%'' or o.name like ''[sfv][pni][__]%'' -- sp__,fn__,vi__ or o.name like ''%[_]tmp'' or o.name like ''%[_]temp'' or o.name like ''%[_]tmp'' or o.name like ''%[_]backup'' or o.name like ''%[_]test'' or o.name like ''%[_][0-9][0-9][0-9][0-9][0-9][0-9][_][0-9][0-9][0-9][0-9]'' -- *_AAMMGG_HHMM ) ) order by xtype,o.name -- save old scrips select @n=count(*) from #objs if @n>0 exec sp__elapsed @timer out,''-- found %d objects to script in:'',@v1=@n else goto err_noobjs exec sp__printf ''-- NB: if occur an error copy and paste code into a new windows to not loose info'' exec sp__printf ''-- NB: search for "keepeye" notes before run scrit'' exec sp__printf ''-- prevent from a too fast F5 running'' exec sp__printf ''declare @secure bit select @secure=1 '' exec sp__printf ''if @secure=1 raiserror(''''Disable @secure first'''',20,1) with log '' exec sp__printf ''GO'' exec sp__printf ''-- goto single user mode'' exec sp__printf ''USE [master] '' exec sp__printf ''ALTER DATABASE [%s] SET SINGLE_USER WITH ROLLBACK IMMEDIATE'',@cur_db exec sp__printf ''ALTER DATABASE [%s] SET SINGLE_USER '',@cur_db exec sp__printf ''USE [%s] '',@cur_db exec sp__printf ''GO'' exec sp__printf ''-- ### scripts objects to convert and save to scripts_...: (%t) ### '',@force=0 -- convert code if @skip_code=1 goto skip_code exec sp__printf ''set nocount on'',@force=0 exec sp__printf ''set transaction isolation level serializable'',@force=0 select @obj=null,@i=min(id),@n=max(id) from #objs while (@i<=@n) begin select @obj=obj,@xtype=xtype from #objs where id=@i select @i=@i+1 if @xtype in (''U'',''F'',''TR'') or @obj in (''sp__script'',''sp__script_reduce'') continue truncate table #src insert #src(line) select ''GO'' -- insert #src(line) select ''begin tran'' insert #src(line) select ''raiserror(''''Dropping & recreating ''+@obj+''...'''',10,1)'' select @sql =''drop '' +case when @xtype in (''P'') then ''proc '' when @xtype in (''FN'',''IF'',''TF'') then ''function '' when @xtype in (''V'') then ''view '' when @xtype in (''U'') then ''table '' end +@obj insert #src(line) select @sql insert #src(line) select ''GO'' exec sp__script @obj,''#src'' exec sp__script_reduce @normalize=4 -- convert to unicode -- insert #src(line) select ''if @@error=0 commit'' -- insert #src(line) select ''if @@trancount>0 begin print ''''rollback of ''+@obj+'''''' rollback end'' insert #src(line) select ''GO'' select @j=null select @k=count(*) from #src select @j=lno/10 from #src where line like ''%ntext%syscomments%'' if not @j is null begin insert into #src(line) select ''-- keepeye: ntext near syscomments can be an error, ''+convert(sysname,@k-@j)+'' lines above'' insert #src(line) select ''GO'' end select @j=null select @k=count(*) from #src select @j=lno/10 from #src where line like ''%substring%8000%'' or line like ''%left%8000%'' or line like ''%right%8000%'' if not @j is null begin insert into #src(line) select ''-- keepeye: 8000 into substring, left, right can be an error, ''+convert(sysname,@k-@j)+'' lines above'' insert #src(line) select ''GO'' end select @j=null select @k=count(*) from #src select @j=lno/10 from #src where line like ''%datalength%'' if not @j is null begin insert into #src(line) select ''-- keepeye: use of datalength can cause error, ''+convert(sysname,@k-@j)+'' lines above'' insert #src(line) select ''GO'' end -- out the code exec sp__script ''#src'' end -- while exec sp__elapsed @timer out,''-- done %d objects in:'',@v1=@n skip_code: -- end of code convertion exec sp__printf ''\n\n-- ### table conversion ###'' exec sp__printf ''-- drop fkeys'',@force=0 exec sp__printf ''raiserror(''''%s'''',10,1)'',''Dropping fkeys...'',@force=0 select @obj=null,@i=min(id),@n=max(id) from #objs while (@i<=@n) begin select @obj=null select @obj=obj,@xtype=xtype,@parent_obj=parent_obj from #objs where id=@i and xtype=''F'' select @i=@i+1 if @obj is null continue -- skip non tables select @tmp=object_name(@parent_obj) select @sql=quotename(parsename(@obj,1)) exec sp__printf ''alter table %s drop constraint %s'',@tmp,@sql end select @obj=null,@i=min(id),@n=max(id) from #objs while (@i<=@n) begin select @obj=null select @obj=obj,@xtype=xtype from #objs where id=@i and xtype=''U'' select @i=@i+1 if @obj is null continue -- skip non tables select @tmp=quotename(''tmp_''+parsename(@obj,1)) select @flds=dbo.fn__flds_of(@obj,'','',null) set @flds=dbo.fn__flds_quotename(@flds,'','') exec sp__printf ''raiserror(''''Converting table %s...'''',10,1)'',@obj,@force=0 exec sp__printf ''\n\n-- converting table:%s:'',@obj,@force=0 exec sp__printf ''declare @rows bigint,@rows_s bigint,@msg sysname'',@force=0 exec sp__printf ''select @rows_s=count(*) from %s'',@obj,@force=0 exec sp__printf ''-- make a backup of data'',@force=0 exec sp__printf ''if dbo.fn__exists(''''%s'''',''''u'''')=1 drop table %s'',@tmp,@tmp,@force=0 exec sp__printf ''select top 0 * into %s from %s with (tablockx)'',@tmp,@obj,@force=0 declare @has_id bit select @has_id=objectproperty(object_id(@obj),''TableHasIdentity'') if @has_id=1 exec sp__printf ''set identity_insert %s on'',@tmp,@force=0 exec sp__printf ''insert into %s(%s) select %s from %s with (tablockx)'',@tmp,@flds,@flds,@obj,@force=0 if @has_id=1 exec sp__printf ''set identity_insert %s off'',@tmp,@force=0 exec sp__printf ''select @msg=convert(sysname,@rows)+'''' rows exported'''''',@force=0 exec sp__printf ''raiserror(@msg,10,1)'',@force=0 exec sp__printf ''select @rows=count(*) from %s'',@tmp,@force=0 exec sp__printf ''if @rows!=@rows_s raiserror(''''there are differences with local backup'''',20,1)'',@force=0 exec sp__printf ''drop table %s'',@obj,@force=0 truncate table #src exec sp__script @obj,''#src'',@oc=@oc_tbl delete from #src where line=''GO'' exec sp__script_reduce @normalize=4 -- convert to unicode exec sp__script ''#src'' if @has_id=1 exec sp__printf ''set identity_insert %s on'',@obj,@force=0 exec sp__printf ''insert into %s(%s) select %s from %s'',@obj,@flds,@flds,@tmp,@force=0 if @has_id=1 exec sp__printf ''set identity_insert %s off'',@obj,@force=0 exec sp__printf ''select @rows=count(*) from %s'',@tmp,@force=0 exec sp__printf ''select @msg=convert(sysname,@rows)+'''' rows imported'''''',@force=0 exec sp__printf ''raiserror(@msg,10,1)'',@force=0 exec sp__printf ''if @rows!=@rows_s raiserror(''''restore of data failed'''',20,1)'',@force=0 truncate table #src exec sp__script @obj,''#src'',@oc=@oc_prp exec sp__script ''#src'' truncate table #src exec sp__script @obj,''#src'',@oc=@oc_dri exec sp__script @obj,''#src'',@oc=@oc_trg exec sp__script_reduce @normalize=4 -- convert to unicode exec sp__script ''#src'' exec sp__printf ''drop table %s'',@tmp,@force=0 end -- while exec sp__printf ''-- reload fkeys'' select @obj=null,@i=min(id),@n=max(id) from #objs while (@i<=@n) begin select @obj=null select @obj=obj,@xtype=xtype,@parent_obj=parent_obj from #objs where id=@i and xtype=''U'' select @i=@i+1 if @obj is null continue -- skip non tables if dbo.fn__exists(@obj,''FK'')=1 begin exec sp__printf ''raiserror(''''Recreating fkey for %s'''',10,1)'',@obj,@force=0 exec sp__script @obj,@oc=@oc_fk end end exec sp__printf ''-- back to multiuser mode'' exec sp__printf ''USE [master] '' exec sp__printf ''ALTER DATABASE [%s] SET MULTI_USER WITH ROLLBACK IMMEDIATE'',@cur_db exec sp__printf ''ALTER DATABASE [%s] SET MULTI_USER '',@cur_db exec sp__printf ''USE [%s] '',@cur_db exec sp__elapsed @timer out,''-- end at %t table script gneration in:'' goto ret err_noobjs: select @msg=''#!no objects to upsize'' goto ret err_noscode: select @msg=''#!no code found in script_code'' goto ret err_compcode: select @msg=''#!compiling sp,fn,v'' goto ret err_compdri: select @msg=''#!compiling dri'' goto ret err_computbl: select @msg=''#!compiling unicoded tables'' goto ret help: select @msg =''Generate script to convert db to unicode'' exec sp__usage @proc,@extra=@msg select @msg=null ret: if not @msg is null exec sp__printf @msg end -- proc sp__util_tounicode' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_tounicode: -- ============================================================== sp__util_users select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_users',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=091216 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_users') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_users') with nowait goto skip_sp__util_users end if @ver>091216 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_users') with nowait goto skip_sp__util_users end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_users') with nowait if exists( select top 1 null from sys.objects where name='sp__util_users' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_users] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:091216\s.zaglio: (in progress) utility for users management c:originally from Gregory A. Larsen */ create proc [dbo].[sp__util_users] as begin set nocount on -- Section 1: Create temporary table to hold databases to process -- drop table if it already exists if (select object_id(''tempdb..##dbnames'')) is not null drop table ##dbnames -- Create table to hold databases to process create table ##dbnames (dbname varchar(128)) -- Section 2: Determine what databases have orphan users exec master.dbo.sp_MSforeachdb ''insert into ##dbnames select ''''?'''' from master..syslogins l right join [?]..sysusers u on l.sid = u.sid where l.sid is null and issqlrole <> 1 and isapprole <> 1 and not (u.name in (''''INFORMATION_SCHEMA'''',''''guest'''',''''system_function_schema'''',''''sys'''',''''dbo'''')) having count(*) > 0'' -- Section 3: Create local variables needed declare @CNT int declare @name char(128) declare @sid varbinary(85) declare @cmd nchar(4000) declare @c int declare @hexnum char(100) declare @db varchar(100) -- Section 5: Process through each database and remove orphan users select @cnt=count(*) from ##DBNAMES While @CNT > 0 begin -- get the name of the top database select top 1 @db=dbname from ##DBNAMES -- delete top database delete from ##DBNAMES where dbname = @db select @db=quotename(@db) -- Build and execute command to determine if DBO is not mapped to login set @cmd = ''select @cnt = count(*) from master..syslogins l right join '' + rtrim(@db) + ''..sysusers u on l.sid = u.sid'' + '' where l.sid is null and u.name = ''''DBO'''''' exec sp_executesql @cmd,N''@cnt int out'',@cnt out -- if DB is not mapped to login that exists map DBO to SA if @cnt = 1 begin print ''exec '' + @db + ''..sp_changedbowner ''''SA'''''' -- exec sp_changedbowner ''SA'' end -- if @cnt = 1 -- drop table if it already exists if (select object_id(''tempdb..##orphans'')) is not null drop table ##orphans -- Create table to hold orphan users create table ##orphans (orphan varchar(128)) -- Build and execute command to get list of all orphan users (Windows and SQL Server) -- for current database being processed set @cmd = ''insert into ##orphans select u.name from master..syslogins l right join '' + rtrim(@db) + ''..sysusers u on l.sid = u.sid '' + ''where l.sid is null and issqlrole <> 1 and isapprole <> 1 '' + ''and not u.name in (''''INFORMATION_SCHEMA'''',''''guest'''', '' + ''''''system_function_schema'''',''''sys'''',''''dbo'''')'' exec (@cmd) -- Are there orphans select @cnt = count(*) from ##orphans WHILE @cnt > 0 BEGIN -- get top orphan select top 1 @name= orphan from ##orphans -- delete top orphan delete from ##orphans where orphan = @name -- Build command to drop user from database. set @cmd = ''exec '' + rtrim(@db) + ''..sp_revokedbaccess '''''' + rtrim(@name) + '''''''' print @cmd --exec (@cmd) -- are there orphans left select @cnt = count(*) from ##orphans end -- WHILE @cnt > 0 -- are the still databases to process select @cnt=count(*) from ##dbnames end -- while @cnt > 0 -- Remove temporary tables drop table ##dbnames, ##orphans end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_users: -- ================================================================ sp__util_vlf select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__util_vlf',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130227 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__util_vlf') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__util_vlf') with nowait goto skip_sp__util_vlf end if @ver>130227 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__util_vlf') with nowait goto skip_sp__util_vlf end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__util_vlf') with nowait if exists( select top 1 null from sys.objects where name='sp__util_vlf' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__util_vlf] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:virtual,log,file,transaction,grow,server,down v:130227\s.zaglio: mixed with sp__util_drives v:120906\s.zaglio: show info about virtual log files todo:explain fields and how to read and what to do c:from http://www.sqlphilosopher.com/wp/category/tsqlproblemsolving/ t:sp__util_vlf run */ CREATE proc sp__util_vlf @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if charindex(''|run|'',@opt)=0 goto help -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit create table #drive_info( letter nchar(1), total_mb bigint, free_mb bigint, label nvarchar(10), [% free] int, dbs nvarchar(4000), logs nvarchar(4000) ) exec sp__util_drives -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == declare @databaselist table ( [database] varchar(256), [executionorder] int identity(1,1) not null ) declare @vlfdensity table ( [server] varchar(256), [database] varchar(256), [size_mb] int null, [growth] sysname null, [density] decimal(7,2), [unusedvlf] int, [usedvlf] int, [totalvlf] int, [drive] sysname null, [drive % free] int null ) declare @loginforesult table ( [fileid] int null, [filesize] bigint null, [startoffset] bigint null, [fseqno] int null, [status] int null, [parity] tinyint null, [createlsn] numeric(25, 0) null ) declare @currentdatabaseid int, @maxdatabaseid int, @dbname varchar(256), @density decimal(7,2), @unusedvlf int, @usedvlf int, @totalvlf int insert into @databaselist ( [database] ) select [name] from [sys].[sysdatabases] select @currentdatabaseid = min([executionorder]), @maxdatabaseid = max([executionorder]) from @databaselist while @currentdatabaseid <= @maxdatabaseid begin select @dbname = [database] from @databaselist where [executionorder] = @currentdatabaseid delete @loginforesult from @loginforesult insert into @loginforesult exec(''dbcc loginfo(['' + @dbname + '']) with no_infomsgs'') select @unusedvlf = count(*) from @loginforesult where [status] = 0 select @usedvlf = count(*) from @loginforesult where [status] = 2 select @totalvlf = count(*) from @loginforesult select @density = convert(decimal(7,2),@usedvlf) / convert(decimal(7,2),@totalvlf) * 100 insert into @vlfdensity ( [server], [database], [density], [unusedvlf], [usedvlf], [totalvlf] ) values ( @@servername, @dbname, @density, @unusedvlf, @usedvlf, @totalvlf ) set @currentdatabaseid = @currentdatabaseid + 1 end update a set size_mb=size*8/1024, growth=case is_percent_growth when 1 then cast(b.growth as sysname)+''%'' else cast(b.growth*8/1024 as sysname)+''MB'' end, [drive]=letter, [drive % free]=[% free] from @vlfdensity a join sys.master_files b on db_name(b.database_id)=a.[database] join #drive_info c on b.physical_name like c.letter+'':%'' -- select * from sys.master_files select [server], [database], [size_mb], [growth], [density], [unusedvlf], [usedvlf], [totalvlf], [drive], [drive % free] from @vlfdensity order by [density] desc drop table #drive_info goto ret -- =================================================================== errors == /* err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope give status about db, disks and virtual log files (TODO: here are to write more explanation) (TODO: can be simplified using DBCC SQLPERF (LOGSPACE)?) Parameters Examples '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__util_vlf' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__util_vlf: -- ===================================================================== sp__web select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__web',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130927.1800 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__web') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__web') with nowait goto skip_sp__web end if @ver>130927.1800 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__web') with nowait goto skip_sp__web end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__web') with nowait if exists( select top 1 null from sys.objects where name='sp__web' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__web] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,web k:soap,web,service,webservice,call,xml,get,pos,send v:130927.1800\s.zaglio: added integrated authentication and refactor of errors v:121022.1213\s.zaglio: removed ext.ns, now is optional and a bug v:121019\s.zaglio: done and tested r:121018\s.zaglio: smart soap call and decode d:121018\s.zaglio: sp__web_get r:121017\s.zaglio: normalized @rcq (cr,lf,tab) r:121016\s.zaglio: testing for bad requests r:121015\s.zaglio: get/set a web resource or call a webservice t:sp__web_test 1 */ CREATE proc sp__web @uri varchar(2000) = null, @method varchar(2000) = null, @ctype nvarchar(255) = null, @rcq nvarchar(max) = null, @sa nvarchar(255) = null, @uid varchar(100) = null, -- Domain\UserName or UserName @pwd varchar(100) = null, @rsp nvarchar(max) = null out, @sts nvarchar(4000) = null out, @opt nvarchar(255) = null, @dbg int=0 as begin try -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp /* a mixed evolution of: from http://www.vishalseth.com/post/2009/12/22/ Call-a-webservice-from-TSQL-%28Stored-Procedure%29-using-MSXML.aspx and https://sourceforge.net/projects/sqldom/ */ declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=case when @opt is null then ''||'' else dbo.fn__str_quote(@opt,''|'') end -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options @nodecode bit,@oxml bit,@soap bit, @ia bit, -- integrated autentication @to_resolve int, @to_connect int, -- timeouts @to_send int, @to_receive int, @crlf varchar(2),@cr char(1),@lf char(1),@tab char(1), @oid int,@hr int,@cmd varchar(255), @len int,@hs_id int, @sa_ns nvarchar(1024), @soap_exception sysname, @params nvarchar(max), @rcqprms_id int, -- if params given @rcqhdrs_id int, -- if more headers given @hre char(2), -- common API error @end_declare bit declare @blob table(blob nvarchar(max)) declare @utf table(utf sysname) -- =========================================================== initialization == select @hre=''hr'', @sts=null,@rsp=null, -- empy for sureness @soap_exception=''System.Web.Services.Protocols.SoapException:'', @nodecode=charindex(''|nodecode|'',@opt), @oxml=charindex(''|oxml|'',@opt), @ia=charindex(''|ia|'',@opt), @crlf=crlf,@cr=cr,@lf=@lf,@tab=tab, @rcqprms_id=isnull(object_id(''tempdb..#rcqprms''),0), @rcqhdrs_id=isnull(object_id(''tempdb..#rcqhdrs''),0), @end_declare=1 from fn__sym() insert @utf select N'''' insert @utf select N'''' -- ======================================================== second params chk == if isnull(@uri,'''')='''' goto help -- ===================================================================== body == -- timeouts if charindex(''|to:'',@opt)>0 begin -- sp__web ''test'',@opt=''to:1000,1000,1000'',@dbg=1 select @to_resolve=case pos when 1 then token else @to_resolve end, @to_connect=case pos when 2 then token else @to_connect end, @to_send =case pos when 3 then token else @to_send end, @to_receive=case pos when 4 then token else @to_receive end from dbo.fn__str_table(dbo.fn__str_between(@opt,''to:'',''|'',default),'','') if @dbg=1 exec sp__printf ''-- to:%d,%d,%d,%d'', @to_resolve,@to_connect,@to_send,@to_receive if not coalesce(@to_resolve,@to_connect,@to_send,@to_receive) is null and (@to_resolve is null or @to_connect is null or @to_send is null or @to_receive is null) raiserror(''all timeouts must be specified'',16,1) end -- timeouts if isnull(@sa,'''')='''' select @ctype=isnull(@ctype,''text/http''), @method=isnull(@method,''GET'') else select @ctype=isnull(@ctype,''text/xml;charset=UTF-8''), @method=isnull(@method,''POST'') -- create ole select @cmd=''MSXML2.ServerXMLHTTP'' exec @hr = sp_oacreate @cmd, @oid out IF @hr!=0 raiserror(@hre,16,1) /* note: exec @hr=sp_oacreate ''winhttp.winhttprequest.5.1'',@@oid out look work well too but do not remembere what limit has need a search on internet */ -- set timeouts if not @to_resolve is null begin select @cmd=''setTimeouts'' exec @hr = sp_OAMethod @oid, @cmd, null, @to_resolve,@to_connect,@to_send,@to_receive IF @hr!=0 raiserror(@hre,16,1) end -- open the destination URI with Specified method select @cmd=''open'' if @ia=0 exec @hr = sp_OAMethod @oid, @cmd, null, @method, @uri, ''false'', @uid, @pwd else exec @hr = sp_OAMethod @oid, @cmd, null, @method, @uri, ''false'' IF @hr!=0 raiserror(@hre,16,1) -- set request headers select @cmd=''setRequestHeader'' exec @hr = sp_OAMethod @oid, @cmd, null, ''Content-Type'', @ctype IF @hr!=0 raiserror(@hre,16,1) -- send the request if @rcqprms_id!=0 begin if not @rcq is null raiserror(''#rcqprms and @rcq cannot be used together'',16,1) if isnull(@sa,'''')='''' raiserror(''missing SOAP Action'',16,1) select @rcq='' '' +case @ia when 0 then '''' else '' '' end+'' <%sa% xmlns="%sa_ns%"> %params% '' select @sa_ns=left(@uri,patindex(''%[a-z0-9_\-\\]/[a-z0-9_\-\\]%'',@uri)) select @i=dbo.fn__charindex(''/'',@sa,-1) if @i>1 select @sa_ns=left(@sa,@i-1),@sa=substring(@sa,@i+1,len(@sa)) select @params=isnull(@params+@crlf,'''')+''<''+var+''>''+val+'''' from #rcqprms exec sp__str_replace @rcq out,''%sa%|%sa_ns%|%uid%|%pwd%'', @sa,@sa_ns,@uid,@pwd select @rcq=replace(@rcq,''%params%'',@params) select @sa=@sa_ns+''/''+@sa end -- use of #rcqprms -- can be used fn__sql_trim but is slower in a repetitive call while left(@rcq,2)=@crlf select @rcq=substring(@rcq,3,len(@rcq)) while left(@rcq,1)=@cr select @rcq=substring(@rcq,2,len(@rcq)) while left(@rcq,1)=@lf select @rcq=substring(@rcq,2,len(@rcq)) select @rcq=ltrim(rtrim(replace(@rcq,@tab,'' ''))) if nullif(@rcq,'''') is null raiserror(''undefined request'',16,1) if @dbg=1 begin exec sp__printf ''-- @uri=%s, @ctype=%s, @method=%s, @sa=%s\n-- request:'', @uri,@ctype,@method,@sa exec sp__printsql @rcq end if isnull(@sa,'''')!='''' select @soap=1 else select @soap=0 -- set soap action if @soap=1 begin select @cmd=''SOAPAction'' exec @hr = sp_oamethod @oid, ''setRequestHeader'', null, @cmd, @sa if @hr!=0 raiserror(@hre,16,1) set @len = len(@rcq) select @cmd=''content-Length'' exec @hr = sp_oamethod @oid, ''setRequestHeader'', null, @cmd, @len if @hr!=0 raiserror(@hre,16,1) end -- more headers if @rcqhdrs_id!=0 begin declare @key nvarchar(500), @val nvarchar(500) declare cs cursor local for select [key],[val] from #rcqhdrs where 1=1 open cs while 1=1 begin fetch next from cs into @key,@val if @@fetch_status!=0 break select @cmd=''setRequestHeader'' exec @hr = sp_oamethod @oid, @cmd, null, @key, @val if @hr!=0 break end -- cursor cs close cs deallocate cs if @hr!=0 raiserror(@hre,16,1) end -- more headers select @cmd=''send'' exec @hr = sp_oamethod @oid, @cmd, null, @rcq if @hr!=0 raiserror(@hre,16,1) -- Get status text select @cmd=''StatusText'' exec sp_OAGetProperty @oid, @cmd, @sts out if @hr!=0 raiserror(@hre,16,1) select @cmd=''Status'' exec sp_OAGetProperty @oid, @cmd, @hs_id out if @hr!=0 raiserror(@hre,16,1) select @sts=cast(@hs_id as sysname) + ''|''+ @sts -- Get response text select @cmd=''responseText'' insert into @blob(blob) exec @hr = sp_OAGetProperty @oid, @cmd -- , @rsp out /* sp_OAGetProperty or any extended sp, do not support varchar(max) however returning as a resulset will return long results */ select top 1 @rsp=blob from @blob if @nodecode=0 select @rsp=dbo.fn__web_html_decode(@rsp) if @soap=1 and @oxml=0 begin -- remove '',@rsp) select @i=charindex(N''<'',@rsp,@i+1) select @n=charindex(N'''',@rsp,@i) select @rsp=substring(@rsp,@i,@n-@i) -- remove most external namespaces select @i=charindex(N''xmlns="'',@rsp) if @i>0 begin select @n=charindex(N''"'',@rsp,@i+7) if @n<@i or @n=0 raiserror(''inside error stripping namespace'',16,1) select @rsp=left(@rsp,@i-1)+substring(@rsp,@n+1,len(@rsp)) end end -- xmp strip if @dbg=1 begin exec sp__printf ''-- response:'' exec sp__printsql @rsp end if not @hs_id in (0,200) begin if charindex(@soap_exception,@rsp)>0 raiserror(''soap exception'',16,1) else raiserror(''status ko'',16,1) end -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. if not @oid is null exec sp_OADestroy @oid goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope get an html page or call a webservice Notes * see "sp__util_advopt" on how disable protection * remember to put N before strings to correctly send unicode chars * ensure that exists in your web.config the parameter: * soap exception and status error raise a error stored into @sts or @rsp (@sts is "500|Internal Server Error" and @rsp contain the System.Web.Services.Protocols.SoapException message) * SOAP ACTION and SOAP PARAMS are CASE SENSITIVE * because the namespace is self-determined by the @sa, some problems can arise where there are more than one namespace Parameters @uri web address @method optional method (default is GET) @ctype content type (default TEXT/HTTP) @rcq data to send or request body @sa optional SOAP action @uid optional Domain\UserName or UserName @pwd optional password @rsp (out)response @sts (out)HTTP Status as id|txt (200=ok, 404=not found, etc.) #rcqhdrs optional multiple request headers create table #rcqhdrs([key] nvarchar(500),val nvarchar(500)) #rcqprms optional to auto fill xml structure to call del SOAP ws create table #rcqprms( id int identity, rid int default(0), var nvarchar(500), val nvarchar(max) ) @opt option description ----------- ---------------------------------------------------- nodecode disable html decode for faster execution to:r,c,r,s set timeouts(ms) for receive,connect,send,receive oxml do not strip SOAP headers but return original xml wslist (TODO) instead of get htm page, get the list of srvs wsdl (TODO) instead of call the SOAP method, get the DL ia @uid & @pwd are passed as integrated authentication Examples see sp__web_ws_test '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end try -- =================================================================== errors == begin catch select @e_msg=error_message() if @e_msg=@hre exec sp_oageterrorinfo @oid,@e_p2 out,@e_p3 out -- destroy ole object if not @oid is null exec sp_OADestroy @oid select @oid=null if @e_msg=@hre begin select @e_msg=''cmd ole "%s" (src:%s; msg:%s)'',@e_p1=@cmd exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3,@opt=''ex'' end else exec @ret=sp__err @cod=@proc,@opt=''ex'' return @ret end catch -- proc sp__web' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__web: -- ============================================================== sp__web_submit select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__web_submit',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120905 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__web_submit') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__web_submit') with nowait goto skip_sp__web_submit end if @ver>120905 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__web_submit') with nowait goto skip_sp__web_submit end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__web_submit') with nowait if exists( select top 1 null from sys.objects where name='sp__web_submit' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__web_submit] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:form, post, submit, simulate, simulation v:120905\s.zaglio: removed dbg info v:120830.1000\s.zaglio: submit html form */ CREATE proc sp__web_submit @url varchar(4000) = null, @params varchar(4000) = null, @ResponseText nvarchar(4000) = null out, -- NO vcMAX! @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == select @url=isnull(@url,''''), @params=isnull(@params,'''') if (@url='''' or @params ='''') -- and @opt=''||'' goto help -- ============================================================== declaration == declare @obj int, @hr int, @src varchar(1000), @desc varchar(1000), @cmd varchar(128) -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == if @dbg=1 exec sp__printf ''-- url:%s\n-- p:%s'',@url,@params select @cmd=''Msxml2.ServerXMLHTTP.3.0'' exec @hr = sp_oaCreate @cmd, @obj OUTPUT if @hr!=0 goto err_ole select @cmd=''Open'' exec @hr = sp_OAMethod @obj, @cmd, null, ''POST'',@url, 0 if @hr!=0 goto err_ole select @cmd=''setRequestHeader'' exec @hr = sp_OAMethod @obj, @cmd, null, ''Content-Type'', ''application/x-www-form-urlencoded'' if @hr!=0 goto err_ole select @cmd=''send'' exec @hr = sp_OAMethod @obj, @cmd, null, @params if @hr!=0 goto err_ole select @cmd=''responseText'' exec @hr = sp_OAGetProperty @obj, @cmd, @ResponseText OUT if @hr!=0 goto err_ole -- Destroy the object dispose: exec @hr = sp_OADestroy @obj select @obj=null goto ret -- =================================================================== errors == err_ole: exec sp_OAGetErrorInfo @obj, @src OUT, @desc OUT exec @ret=sp__err ''"%s" in "%s" for OLE cmd %s'',@proc, @p1=@desc,@p2=@src,@p3=@cmd goto dispose -- ===================================================================== help == help: exec sp__usage @proc,'' Scope submit html form Parameters @url target address (tipical ACTION tag) @params form parameters (tipical INPUT tag): param1=val1¶m2=val2¶m3=... @ResponseText the returned html/text @opt options (not used) @dbg debug 1 print some info Examples '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__web_submit' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__web_submit: -- ================================================================ sp__web_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__web_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121019 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__web_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__web_test') with nowait goto skip_sp__web_test end if @ver>121019 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__web_test') with nowait goto skip_sp__web_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__web_test') with nowait if exists( select top 1 null from sys.objects where name='sp__web_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__web_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,web,test v:121019\s.zaglio: done test 4 and xml extraction r:121018\s.zaglio: testing smart soap call r:121017\s.zaglio: adapted sp__web_ws to null prev bugs r:121016\s.zaglio: bug near N'' and crlf r:121015\s.zaglio: test sp__web_ws t:sp__web_test ''all'',@dbg=1 */ CREATE proc sp__web_test @tst sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @crlf nvarchar(2), @response nvarchar(max), @status nvarchar(4000), @url nvarchar(1024), @sa nvarchar(1024), @xml xml, @end_declare bit -- =========================================================== initialization == select -- @opt1=charindex(''|opt|'',@opt), @crlf=crlf, @tst=isnull(@tst,''''), @end_declare=1 from fn__sym() -- ======================================================== second params chk == if @tst='''' goto help if @tst=''all'' select @tst=''0'' if isnumeric(@tst)=0 goto err_tst if @tst<0 or @tst>4 goto err_tst -- ===================================================================== body == -- sp__web_test run,@dbg=1 if @tst in (0,1) begin exec sp__prints ''simple url get'' select @url=''http://www.webservicex.com/stockquote.asmx/GetQuote?symbol=MSFT'' exec @ret=sp__web @url,@rsp=@response out,@sts=@status out,@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''ret=%d, status=%s'',@ret,@status end -- sp__web_test 2,@dbg=1 if @tst in (0,2) begin exec sp__prints ''not exists test'' select @url=''http://www.thisdonotexist.exw/i.html'' exec @ret=sp__web @url,@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''ret=%d, status=%s'',@ret,@status exec sp__prints ''bad method'' select @url=''http://www.webservicex.com/stockquote.asmx/GetQuote?symbol=MSFT'' exec @ret=sp__web @url,''got'',@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''ret=%d, status=%s'',@ret,@status end -- sp__web_test 3,@dbg=1 if @tst in (0,3) begin exec sp__prints ''web service test with timeouts and xml parse'' select @url=''http://www.webservicex.net/globalweather.asmx'' exec @ret=sp__web @url, @rsp=@response out, @sa=''http://www.webserviceX.NET/GetWeather'', @rcq='' brescia italy '' ,@opt=''to:1000,1000,1000,1000'' ,@sts=@status out,@dbg=@dbg --,@opt=''nodecode'' if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''ret=%d, status=%s'',@ret,@status -- extract xml data select @xml = cast(@response as xml) select t.c.value(''Location[1]'', ''nvarchar(20)'') as ''Location'', t.c.value(''Time[1]'', ''nvarchar(10)'') as ''Time'', t.c.value(''Wind[1]'', ''nvarchar(50)'') as ''Wind'', t.c.value(''Visibility[1]'', ''nvarchar(200)'') as ''Visibility'', -- alternative direct method @xml.value(''(//CurrentWeather/SkyConditions)[1]'', ''nvarchar(20)'') SkyCond, @xml.value(''(//CurrentWeather/temperature)[1]'', ''nvarchar(20)'') Temp, -- case sensitive @xml.value(''(//CurrentWeather/DewPoint)[1]'', ''nvarchar(20)'') DewPoint, @xml.value(''(//CurrentWeather/RelativeHumidity)[1]'', ''nvarchar(20)'') Humidity, @xml.value(''(//CurrentWeather/Pressure)[1]'', ''nvarchar(20)'') Pressure, @xml.value(''(//CurrentWeather/Status)[1]'', ''nvarchar(20)'') Status from @xml.nodes(''//CurrentWeather'') t(c) end -- test 3 -- sp__web_test 4,@dbg=1 if @tst in (0,4) begin exec sp__prints ''smart SOAP call'' create table #rcqprms( id int identity, rid int default(0), var nvarchar(500), val nvarchar(max) ) insert #rcqprms(var,val) select ''CityName'',''brescia'' insert #rcqprms(var,val) select ''CountryName'',''italy'' select @url=''http://www.webserviceX.NET/globalweather.asmx'', @sa =''GetWeather'' exec @ret=sp__web @uri=@url, @sa=@sa,@sts=@status out,@rsp=@response out ,@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''ret=%d, status=%s'',@ret,@status drop table #rcqprms end -- soap smart call -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_tst: select @e_msg=''wrong @tst value'' goto err -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test the sp__web_ws: 1. simple test (get a url) 2. wrong test (bad url) 3. wrong method (got instead of get) Parameters @tst id of specific test 1 test simple get 2 test wrong params 3 test SOAP call 4 test SOAP smart call ALL all above @opt options (not used) '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__web_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__web_test: -- ================================================================ sp__web_tool select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__web_tool',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=120905 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__web_tool') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__web_tool') with nowait goto skip_sp__web_tool end if @ver>120905 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__web_tool') with nowait goto skip_sp__web_tool end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__web_tool') with nowait if exists( select top 1 null from sys.objects where name='sp__web_tool' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__web_tool] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility k:html,parse,get,table v:120905\s.zaglio: quiet out, use dbg to show info v:120824.1400\s.zaglio: get a table but not all r:120823\s.zaglio: add temp SP for web operations t:sp__web_tool @opt=''install'' */ CREATE proc sp__web_tool @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int -- @ret: 0=OK -1=HELP, any=error id select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == if @opt=''||'' goto help -- ============================================================== declaration == -- declare -- insert before here -- @end_declare bit -- =========================================================== initialization == -- select -- insert before here -- @end_declare=1 -- ======================================================== second params chk == -- ===================================================================== body == -- ########################## -- ## -- ## BEGIN OF RUETER''S CODE -- ## -- ######################################################## /* SQLDOM HTML parser and DOM tools for MSSQL. https://sourceforge.net/projects/sqldom/ Parses HTML from a string or from a URL into a DOM (document object model) implemented with SQL tables. Provides routines to manipulate the DOM data and to render the DOM data back to HTML. You may safely run this entire script: it does not make any changes to any SQL user databases. It only creates some local temporary tables and temporary stored procedures, and prints out a string with some instructions. Requires Microsoft SQL 2005 or later. Copyright (C) 2012 David B. Rueter (drueter@assyst.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. HISTORY Version .924 4/24/2012 Fixed attribute handling to support attributes without values (such as < option selected>My Option) Thanks to JMelin for reporting. Version .923 4/3/2012 Fixed additional bug in #spgetDOM pertaining to getting by selector. Version .922 3/20/2012 Fixed bug in #spgetDOM pertaining to getting by selector. Thanks to Brian Hurtt for reporting and providing correction. Version .921 3/5/2012 Added #sputilConvertJSONToXML to convert JSON data to XML Version .920 2/23/2012 Refactor #spgetDOMHTML to fix bugs, streamline Version .919 2/21/2012 Corrected problem with rendering HTML comments Version .918 2/20/2012 Removed dependencies on 3 UDF string helper functions Performance increase (approx. 23%) Clean up some comments Version .917 2/19/2012 Initial public version */ SET NOCOUNT ON IF OBJECT_ID(''tempdb..#spactTrimWhitespace'') IS NOT NULL BEGIN DROP PROCEDURE #spactTrimWhitespace END IF OBJECT_ID(''tempdb..#spgetLenNTW'') IS NOT NULL BEGIN DROP PROCEDURE #spgetLenNTW END if charindex(''|keep|'',@opt)=0 begin IF OBJECT_ID(''tempdb..#tblDOMDocs'') IS NOT NULL BEGIN DROP TABLE #tblDOMDocs END IF OBJECT_ID(''tempdb..#tblDOM'') IS NOT NULL BEGIN DROP TABLE #tblDOM END IF OBJECT_ID(''tempdb..#tblDOMAttribs'') IS NOT NULL BEGIN DROP TABLE #tblDOMAttribs END IF OBJECT_ID(''tempdb..#tblDOMStyles'') IS NOT NULL BEGIN DROP TABLE #tblDOMStyles END end -- keep option IF OBJECT_ID(''tempdb..#spactDOMOpen'') IS NOT NULL BEGIN DROP PROCEDURE #spactDOMOpen END IF OBJECT_ID(''tempdb..#spgetDOM'') IS NOT NULL BEGIN DROP PROCEDURE #spgetDOM END IF OBJECT_ID(''tempdb..#spgetDOMHTML'') IS NOT NULL BEGIN DROP PROCEDURE #spgetDOMHTML END IF OBJECT_ID(''tempdb..#spactDOMLoad'') IS NOT NULL BEGIN DROP PROCEDURE #spactDOMLoad END IF OBJECT_ID(''tempdb..#spinsDOMNode'') IS NOT NULL BEGIN DROP PROCEDURE #spinsDOMNode END IF OBJECT_ID(''tempdb..#spactDOMClear'') IS NOT NULL BEGIN DROP PROCEDURE #spactDOMClear END IF OBJECT_ID(''tempdb..#spupdDOMAttribs'') IS NOT NULL BEGIN DROP PROCEDURE #spupdDOMAttribs END IF OBJECT_ID(''tempdb..#spupdDOMStyles'') IS NOT NULL BEGIN DROP PROCEDURE #spupdDOMStyles END IF OBJECT_ID(''tempdb..#sputilGetHTTP'') IS NOT NULL BEGIN DROP PROCEDURE #sputilGetHTTP END IF OBJECT_ID(''tempdb..#sputilConvertJSONToXML'') IS NOT NULL BEGIN DROP PROCEDURE #sputilConvertJSONToXML END if charindex(''|uninstall|'',@opt)>0 goto ret if charindex(''|install|'',@opt)>0 begin /* ************************************************************************************** PROCEDURE #spactTrimWhitespace Simple helper function to do a left-trim or right-trim of whitespace (spaces, tabs, carriage returns and linefeeds, and tabs). I would really prefer this to be a function, but we are not allowed to create temporary functions, and I do not want SQLDOM to require permanent database objects. ************************************************************************************** */ exec('' CREATE PROCEDURE #spactTrimWhitespace @S varchar(MAX) OUTPUT, @DoLeft bit = 0, @DoRight bit = 1 AS BEGIN DECLARE @P int IF @DoRight = 1 BEGIN --Right trim SET @P = LEN(@S + ''''x'''') - 1 WHILE @P >= 1 BEGIN IF ISNULL(SUBSTRING(@S, @P, 1), '''' '''') IN ('''' '''', CHAR(9), CHAR(10), CHAR(13)) BEGIN SET @P = @P - 1 END ELSE BEGIN BREAK END END SET @S= LEFT(@S, @P) END IF @DoLeft = 1 BEGIN --Left trim SET @P = 1 WHILE @P <= LEN(@S + ''''x'''') - 1 BEGIN IF SUBSTRING(@S, @P, 1) IN ('''' '''', CHAR(9), CHAR(10), CHAR(13)) BEGIN SET @P = @P + 1 END ELSE BEGIN BREAK END END SET @S = RIGHT(@S, LEN(@S + ''''x'''') - 1 - @P + 1) END END '') /* ************************************************************************************** PROCEDURE #spgetLenNTW (no trailing whitespace) Simple helper function to determine the length of a string after trimming all trailing whitespace (spaces, tabs, carriage returns and linefeeds, and tabs). I would really prefer this to be a function, but we are not allowed to create temporary functions, and I do not want SQLDOM to require permanent database objects. ************************************************************************************** */ exec('' CREATE PROCEDURE #spgetLenNTW @S varchar(MAX), @Len int OUTPUT AS BEGIN SET @Len = LEN(@S + ''''x'''') - 1 DECLARE @Done bit SET @Done = 0 WHILE @Done = 0 BEGIN IF (@Len > 0) AND (SUBSTRING(@S, @Len, 1) IN (CHAR(9), CHAR(10), CHAR(13), '''' '''')) BEGIN SET @Len = @Len - 1 END ELSE BEGIN SET @Done = 1 END END END '') /* ************************************************************************************** PROCEDURE #spactDOMOpen Procedure #spactDOMOpen verifies session and @DocID ************************************************************************************** */ exec('' CREATE PROCEDURE #spactDOMOpen @DocID int OUTPUT, @CreateNew bit = 0 AS BEGIN --Note: if @DocID is provided, we trust it. We don''''t validate that it exists --or that it belongs to this session. IF (@CreateNew = 1) BEGIN IF @DocID IS NOT NULL BEGIN RAISERROR(''''Error in #spactDOMOpen: Cannot specify @DocID if @CreateNew=1'''', 16, 1) END INSERT INTO #tblDOMDocs (DateCreated) VALUES (GETDATE()) SET @DocID = SCOPE_IDENTITY() END ELSE BEGIN IF @DocID IS NOT NULL BEGIN IF NOT EXISTS (SELECT DocID FROM #tblDomDocs WHERE DocID = @DocID) BEGIN RAISERROR(''''Error in #spactDOMOpen: Invalid @DocID specified.'''', 16, 1) END END ELSE BEGIN --Open a new DOM Document DECLARE @DocCount int IF @DocID IS NULL BEGIN SELECT @DocCount = COUNT(doc.DocID), @DocID = MIN(doc.DocID) FROM #tblDOMDocs doc IF @DocCount > 1 BEGIN RAISERROR(''''Error in #spactDOMOpen: @DocID was not specified, and there are multiple documents present in this session.'''', 16, 1) END ELSE IF @DocID IS NULL BEGIN INSERT INTO #tblDOMDocs (DateCreated) VALUES (GETDATE()) SET @DocID = SCOPE_IDENTITY() END END END END END '') /* ************************************************************************************** PROCEDURE #spactDOMClear Procedure #spactDOMClear clears all data in the DOM ************************************************************************************** */ exec('' CREATE PROCEDURE #spactDOMClear @DocID int = NULL OUTPUT AS BEGIN DELETE FROM #tblDOMAttribs WHERE DEID IN (SELECT DEID FROM #tblDOM WHERE @DocID IS NULL OR DocID = @DocID) DELETE FROM #tblDOMStyles WHERE DEID IN (SELECT DEID FROM #tblDOM WHERE @DocID IS NULL OR DocID = @DocID) DELETE FROM #tblDOM WHERE @DocID IS NULL OR DocID = @DocID END '') /* ************************************************************************************** PROCEUDRE #spupdDOMAttribs Procedure #spupdDOMAttribs is to set Attributes of existing elements in the DOM ************************************************************************************** */ exec('' CREATE PROCEDURE #spupdDOMAttribs @DocID int = NULL OUTPUT, @DEID int = NULL, @ID varchar(512) = NULL, @Name varchar(512) = NULL, @Value varchar(MAX) = NULL, @Attribs varchar(MAX) = NULL, @Selector varchar(MAX) = NULL AS BEGIN SET @Value = NULLIF(RTRIM(@Value), '''''''') IF @DocID IS NULL EXEC #spactDOMOpen @DocID = @DocID OUTPUT DECLARE @tvTargetList TABLE ( DEID int PRIMARY KEY ) IF @ID IS NOT NULL BEGIN SELECT @DEID = dom.DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.ID = @ID END ELSE IF @Selector IS NOT NULL BEGIN INSERT INTO @tvTargetList (DEID) EXEC #spgetDOM @DocID = @DocID OUTPUT, @Selector = @Selector, @ReturnDEIDsOnly = 1 SELECT TOP 1 @DEID = DEID FROM @tvTargetList END WHILE @DEID IS NOT NULL BEGIN IF ISNULL(RTRIM(@Attribs), '''''''') = '''''''' BEGIN DECLARE @TargetID int SELECT @TargetID = atr.DomAttribID FROM #tblDOMAttribs atr WHERE atr.DEID = @DEID AND atr.Name = @Name IF @TargetID IS NOT NULL BEGIN IF @Value IS NULL BEGIN DELETE FROM #tblDOMAttribs WHERE DOMAttribID = @TargetID END ELSE BEGIN UPDATE #tblDOMAttribs SET Value = @Value WHERE DOMAttribID = @TargetID END END ELSE BEGIN INSERT INTO #tblDOMAttribs ( DEID, Name, Value) VALUES ( @DEID, @Name, @Value ) END --Assign special attributes UPDATE dom SET ID = ISNULL(at_id.Value, dom.ID), Name = ISNULL(at_name.Value, dom.Name), Class = ISNULL(at_class.Value, dom.Class) FROM #tblDOM dom LEFT JOIN #tblDOMAttribs at_id ON dom.DEID = at_id.DEID AND at_id.Name = ''''id'''' LEFT JOIN #tblDOMAttribs at_name ON dom.DEID = at_name.DEID AND at_name.Name = ''''name'''' LEFT JOIN #tblDOMAttribs at_class ON dom.DEID = at_class.DEID AND at_class.Name = ''''class'''' WHERE dom.DocID = @DocID AND dom.DEID = @DEID DELETE FROM #tblDOMAttribs WHERE DEID = @DEID AND Name in (''''id'''', ''''name'''', ''''class'''') END ELSE BEGIN IF RTRIM(ISNULL(@Attribs, '''''''')) <> '''''''' BEGIN --Parse out attributes DECLARE @i int DECLARE @c char DECLARE @State varchar(40) DECLARE @InQuote bit DECLARE @NameStr varchar(MAX) DECLARE @ValueStr varchar(MAX) DECLARE @StartQuote char DECLARE @DoAttrib bit SET @InQuote = 0 SET @StartQuote = NULL SET @State = ''''AttribName'''' SET @i = 1 SET @NameStr = '''''''' SET @ValueStr = '''''''' WHILE @i <= LEN(@Attribs) BEGIN SET @c = SUBSTRING(@Attribs, @i, 1) IF (@State = ''''AttribValue'''') BEGIN IF (@c IN (''''"'''', '''''''''''''''')) BEGIN IF (@InQuote = 0) AND ((@StartQuote IS NULL) OR (@c = @StartQuote)) BEGIN SET @InQuote = 1 IF @StartQuote IS NULL BEGIN SET @StartQuote = @c END END ELSE IF (@InQuote = 1) AND (@c = @StartQuote) BEGIN SET @InQuote = 0 IF (@i >= 2) AND (SUBSTRING(@Attribs, @i -1 , 1) = @c) BEGIN SET @ValueStr = @ValueStr + @C END END ELSE IF @c <> @StartQuote BEGIN SET @ValueStr = @ValueStr + @c END END ELSE BEGIN SET @ValueStr = @ValueStr + @c END IF ((@c = '''' '''') AND @InQuote = 0) OR (@i = LEN(@Attribs)) BEGIN SET @DoAttrib = 1 SET @State = ''''AttribName'''' END END ELSE BEGIN IF @State = ''''AttribName'''' BEGIN IF @c = ''''='''' BEGIN SET @State = ''''AttribValue'''' END ELSE IF (@c = '''' '''') BEGIN SET @DoAttrib = 1 END ELSE IF @i = LEN(@Attribs) BEGIN SET @NameStr = @NameStr + @c SET @DoAttrib = 1 END ELSE BEGIN IF @c <> '''' '''' BEGIN SET @NameStr = @NameStr + @c END END END END IF @DoAttrib = 1 BEGIN SET @DoAttrib = 0 EXEC #spupdDOMAttribs @DocID = @DocID OUTPUT, @DEID = @DEID, @Name = @NameStr, @Value = @ValueStr SET @NameStr = '''''''' SET @ValueStr = '''''''' END SET @i = @i + 1 END END END DELETE FROM @tvTargetList WHERE DEID = @DEID SET @DEID = NULL IF EXISTS(SELECT DEID FROM @tvTargetList) BEGIN SELECT TOP 1 @DEID = DEID FROM @tvTargetList END END END '') /* ************************************************************************************** PROCEDURE #spinsDOMNode Procedure #spinsDOMNode is to ADD elements to the DOM ************************************************************************************** */ exec('' CREATE PROCEDURE #spinsDOMNode @DocID int = NULL OUTPUT, @Tag varchar(MAX), @ID varchar(512) = NULL, @Name varchar(512) = NULL, @Class varchar(512) = NULL, @Text varchar(MAX) = NULL, @Attribs varchar(MAX) = NULL, @OpenTagStartPos int = NULL, @CloseTagEndPos int = NULL, @ParentID varchar(512) = NULL, @ParentDEID int = NULL, @DEID int = NULL OUTPUT AS BEGIN /* Adds the specified node to the #tblDOM. If @Tag is specified, but @Text is not specified, a single normal node is added. If @Text is specified, then TWO nodes are added: one for the specified @Tag, and then a child text node. (Text nodes have only the TextData and the ParentDEID: they do not have tags or other attributes.) If @Tag is null, then only a text node is added. It is added as a child of the parent that was specified. HTML comments are a special case. For these the tag will be !-- and the comment node itself will store the comment body in TextData. TextData will contain the start and end tags for the comment (such as ). There will not be a child text node. If @ParentID is specified, #tblDOM is searched for an existing node that has the specified HTML ID. If found, the corresponding ParentDEID will be used as the parent for the new node. Alternately, @ParentDEID may be spedified directly. If both @ParentID and @ParentDEID are null, then the node will be added with a null parent-- which indicates that it is a top level (or root level) node. */ IF @DocID IS NULL EXEC #spactDOMOpen @DocID = @DocID OUTPUT IF @ParentID IS NOT NULL BEGIN SELECT @ParentDEID = dom.DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.ID = @ParentID END SET @DEID = NULL IF (@Tag IS NOT NULL) BEGIN INSERT INTO #tblDOM ( DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID) VALUES ( @DocID, LOWER(@Tag), @ID, @Name, @Class, CASE WHEN (@Tag = ''''!--'''') THEN @Text ELSE NULL END, @OpenTagStartPos, @CloseTagEndPos, @ParentDEID) SET @DEID = SCOPE_IDENTITY() SET @ParentDEID = @DEID --Store attributes IF ISNULL(RTRIM(@Attribs), '''''''') <> '''''''' BEGIN EXEC #spupdDOMAttribs @DocID = @DocID OUTPUT, @DEID = @DEID, @Attribs = @Attribs END END IF (ISNULL(@Tag, '''''''') <> ''''!--'''') AND (@Text IS NOT NULL) BEGIN INSERT INTO #tblDOM ( DocID, Tag, ID, Name, Class, TextData, ParentDEID) SELECT @DocID, NULL AS Tag, NULL AS ID, NULL AS Name, NULL AS Class, @Text, @ParentDEID END END '') /* ************************************************************************************** PROCEDURE #spupdDOMStyles Procedure #spupdDOMStyles is to set Styles of existing elements in the DOM ************************************************************************************** */ exec('' CREATE PROCEDURE #spupdDOMStyles @DocID int = NULL, @DEID int = NULL, @ID varchar(512) = NULL, @Name varchar(512), @Value varchar(MAX) AS BEGIN IF @DocID IS NULL EXEC #spactDOMOpen @DocID = @DocID OUTPUT IF @ID IS NOT NULL BEGIN SELECT @DEID = dom.DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.ID = @ID END ELSE BEGIN SELECT @DEID = dom.DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.DEID = @DEID END DECLARE @TargetID int SELECT @TargetID = DOMStyleID FROM #tblDOMStyles WHERE DEID = @DEID AND Name = @Name IF @TargetID IS NOT NULL BEGIN IF @Value IS NULL BEGIN DELETE FROM #tblDOMStyles WHERE DOMStyleID = @TargetID END ELSE BEGIN UPDATE #tblDOMStyles SET Value = @Value WHERE DOMStyleID = @TargetID END END ELSE BEGIN INSERT INTO #tblDOMStyles ( DEID, Name, Value) VALUES ( @DEID, @Name, @Value ) END END '') /* *******************************************************************4******************* PROCEDURE #spgetDOM Procedure #spgetDOM is to retrive the internal DOM information as a resultset. Provides JQuery-like functionality to select nodes from the DOM based on the specified selector. The selector can indicate #classes, .id''''s or tags. If @Selector = NULL, the entire DOM will be returned. ************************************************************************************** */ exec('' CREATE PROCEDURE #spgetDOM @DocID int = NULL OUTPUT, @Selector varchar(900) = NULL, @ReturnDEIDsOnly bit = 0 AS BEGIN IF @DocID IS NULL EXEC #spactDOMOpen @DocID = @DocID OUTPUT IF @Selector IS NULL BEGIN --CTE Start ----------------------- ;WITH DOMTree ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) AS ( SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS HUID, CAST(RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, 1 AS DOMLevel FROM #tblDOM dom WHERE dom.ParentDEID IS NULL UNION ALL SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(domch.HUID + ''''.'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS varchar(900)) AS HUID, CAST(domch.SortHUID + ''''.'''' + RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, domch.DOMLevel + 1 FROM DOMTree domch JOIN #tblDOM dom ON domch.DEID = dom.ParentDEID ) --CTE End ----------------------- SELECT * FROM DOMTree dom WHERE dom.DocID = @DocID ORDER BY dom.SortHUID END ELSE BEGIN SET @Selector = RTRIM(@Selector) + '''' '''' DECLARE @c char DECLARE @i int DECLARE @Mode varchar(40) DECLARE @SelWhere varchar(MAX) DECLARE @SelTerm varchar(MAX) --default selector is Tag SET @Mode = ''''tag'''' SET @i = 1 WHILE @i <= LEN(@Selector) BEGIN SET @c = SUBSTRING(@Selector, @i, 1) IF @c IN (''''.'''', ''''#'''', '''' '''') BEGIN IF @c = ''''.'''' BEGIN SET @Mode = ''''id'''' END ELSE IF @c = ''''#'''' BEGIN SET @Mode = ''''class'''' END ELSE IF @C = '''' '''' BEGIN --apply selector SET @SelWhere = ISNULL(@SelWhere + '''' AND '''', '''''''') + @SelTerm END SET @SelTerm = NULL END ELSE BEGIN SET @SelTerm = ISNULL(@SelTerm, '''''''') + @c END SET @i = @i + 1 END IF @ReturnDEIDsOnly = 1 BEGIN IF @Mode = ''''class'''' BEGIN SELECT DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.Class = @SelTerm END ELSE IF @Mode = ''''id'''' BEGIN SELECT DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.ID = @SelTerm END ELSE IF @Mode = ''''tag'''' BEGIN SELECT DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.Tag = @SelTerm END END ELSE BEGIN IF @Mode = ''''class'''' BEGIN --CTE Start ----------------------- ;WITH DOMTree ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) AS ( SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS HUID, CAST(RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, 1 AS DOMLevel FROM #tblDOM dom WHERE dom.ParentDEID IS NULL UNION ALL SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(domch.HUID + ''''.'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS varchar(900)) AS HUID, CAST(domch.SortHUID + ''''.'''' + RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, domch.DOMLevel + 1 FROM DOMTree domch JOIN #tblDOM dom ON domch.DEID = dom.ParentDEID ) --CTE End ----------------------- SELECT dt.DEID, dt.DocID, dt.Tag, dt.ID, dt.Name, dt.Class, dt.TextData, dt.OpenTagStartPos, dt.CloseTagEndPos, dt.ParentDEID, dt.HUID, dt.SortHUID, dt.DOMLevel, ROW_NUMBER() OVER (ORDER BY dt.SortHUID) AS Sequence FROM DomTree dt JOIN #tblDOMDocs doc ON dt.DocID = doc.DocID WHERE dt.DocID = @DocID AND dt.Class = @SelTerm ORDER BY dt.sortHUID END ELSE IF @Mode = ''''id'''' BEGIN --CTE Start ----------------------- ;WITH DOMTree ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) AS ( SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS HUID, CAST(RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, 1 AS DOMLevel FROM #tblDOM dom WHERE dom.ParentDEID IS NULL UNION ALL SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(domch.HUID + ''''.'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS varchar(900)) AS HUID, CAST(domch.SortHUID + ''''.'''' + RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, domch.DOMLevel + 1 FROM DOMTree domch JOIN #tblDOM dom ON domch.DEID = dom.ParentDEID ) --CTE End ----------------------- SELECT dt.DEID, dt.DocID, dt.Tag, dt.ID, dt.Name, dt.Class, dt.TextData, dt.OpenTagStartPos, dt.CloseTagEndPos, dt.ParentDEID, dt.HUID, dt.SortHUID, dt.DOMLevel, ROW_NUMBER() OVER (ORDER BY dt.SortHUID) AS Sequence FROM DomTree dt JOIN #tblDOMDocs doc ON dt.DocID = doc.DocID WHERE dt.DocID = @DocID AND dt.ID = @SelTerm ORDER BY dt.sortHUID END ELSE IF @Mode = ''''tag'''' BEGIN --CTE Start ----------------------- ;WITH DOMTree ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) AS ( SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS HUID, CAST(RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, 1 AS DOMLevel FROM #tblDOM dom WHERE dom.ParentDEID IS NULL UNION ALL SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(domch.HUID + ''''.'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS varchar(900)) AS HUID, CAST(domch.SortHUID + ''''.'''' + RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, domch.DOMLevel + 1 FROM DOMTree domch JOIN #tblDOM dom ON domch.DEID = dom.ParentDEID ) --CTE End ----------------------- SELECT dt.DEID, dt.DocID, dt.Tag, dt.ID, dt.Name, dt.Class, dt.TextData, dt.OpenTagStartPos, dt.CloseTagEndPos, dt.ParentDEID, dt.HUID, dt.SortHUID, dt.DOMLevel, ROW_NUMBER() OVER (ORDER BY dt.SortHUID) AS Sequence FROM DomTree dt JOIN #tblDOMDocs doc ON dt.DocID = doc.DocID WHERE dt.DocID = @DocID AND dt.Tag = @SelTerm ORDER BY dt.sortHUID END END END END '') /* ************************************************************************************** PROCEDURE #spgetDOMHTML Procedure #spgetDOMHTML is to render an HTML string based on the internal data in the DOM ************************************************************************************** */ exec('' CREATE PROCEDURE #spgetDOMHTML @DocID int = NULL OUTPUT, @ForceDocType varchar(MAX) = NULL, @PrettyWhitespace bit = 0, @HTML varchar(MAX) = NULL OUTPUT, @PrintHTML bit = 1 AS BEGIN DECLARE @Debug bit SET @Debug = 0 IF @DocID IS NULL EXEC #spactDOMOpen @DocID = @DocID OUTPUT --temp table to hold local copy of DOM output by #DOM CREATE TABLE #Render( DEID int PRIMARY KEY, DocID int, Tag varchar(MAX), ID varchar(512), Name varchar(512), Class varchar(512), TextData varchar(MAX), OpenTagStartPos int, CloseTagEndPos int, ParentDEID int, HUID varchar(900), SortHUID varchar(900), DOMLevel int, Sequence int, HasChild bit ) CREATE INDEX ixtmpRender_SortHUID ON #Render (SortHUID) CREATE INDEX ixtmpRender_Sequence ON #Render (Sequence) --local table to hold stack of tags DECLARE @tvTagStack TABLE ( StackID int identity PRIMARY KEY, --facilitates deletes DEID int, CloseTag varchar(900) ); DECLARE @CRLF varchar(5) SET @CRLF = CHAR(13) + CHAR(10) INSERT INTO #Render ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) EXEC #spgetDOM @DocID = @DocID OUTPUT UPDATE r SET Sequence = r_seq.Sequence FROM #Render r JOIN ( SELECT r.DEID, ROW_NUMBER() OVER (ORDER BY r.SortHUID) AS Sequence FROM #Render r ) r_seq ON r.DEID = r_seq.DEID UPDATE r SET HasChild = CASE WHEN r2.DOMLevel > r.DOMLevel THEN 1 ELSE 0 END FROM #Render r JOIN #Render r2 ON r.Sequence + 1 = r2.Sequence DECLARE curDOM CURSOR LOCAL STATIC FOR SELECT r.DEID, r.Tag, r.ID, r.Name, r.Class, r.TextData, r.ParentDEID, r.HUID, r.DOMLevel, r.HasChild FROM #Render r ORDER BY r.Sequence DECLARE @DEID int DECLARE @Tag varchar(MAX) DECLARE @ID varchar(512) DECLARE @Name varchar(512) DECLARE @Class varchar(512) DECLARE @TextData varchar(MAX) DECLARE @ParentDEID int DECLARE @HUID varchar(900) DECLARE @DOMLevel int DECLARE @HasChild bit DECLARE @RenderedHTML varchar(MAX) DECLARE @DonePop bit DECLARE @AllowPush bit DECLARE @StackID int DECLARE @StackDEID int DECLARE @StackTag varchar(MAX) DECLARE @EmitTag varchar(MAX) DECLARE @ThisStyle varchar(MAX) DECLARE @ThisAttribID int DECLARE @LastAttribID int DECLARE @ThisAttribName varchar(MAX) DECLARE @ThisAttribValue varchar(MAX) DECLARE @CurParentDEID int DECLARE @CurParentTag varchar(MAX) OPEN curDOM FETCH curDOM INTO @DEID, @Tag, @ID, @Name, @Class, @TextData, @ParentDEID, @HUID, @DOMLevel, @HasChild SET @RenderedHTML = NULL SET @CurParentDEID = NULL SET @CurParentTag = NULL SET @DonePop = NULL WHILE @@FETCH_STATUS = 0 BEGIN --Walk through each node of the DOM to render HTML SET @ThisStyle = NULL SET @ThisAttribID = NULL SET @LastAttribID = NULL SET @EmitTag = NULL SET @AllowPush = NULL SET @StackID = NULL SET @StackDEID = NULL SET @StackTag = NULL IF @DonePop IS NULL BEGIN --first pass through SET @CurParentDEID = @ParentDEID SET @CurParentTag = '''''''' SET @DonePop = 1 END IF @Debug = 1 PRINT ''''Starting node @Tag = '''' + ISNULL(@Tag, ''''NULL'''') + '''' @DEID = '''' + ISNULL(CAST(@DEID AS varchar(100)), ''''NULL'''') + '''' @ParentDEID = '''' + ISNULL(CAST(@ParentDEID AS varchar(100)), ''''NULL'''') + '''' @CurParentDEID = '''' + ISNULL(CAST(@CurParentDEID AS varchar(100)), ''''NULL'''') --#1: See if there is anything we need to pop. Close tags, set CurParent as needed. IF ISNULL(@ParentDEID, 0) <> ISNULL(@CurParentDEID, 0) --AND -- (@Tag IS NOT NULL) AND (@Tag NOT LIKE ''''!%'''') BEGIN IF @Debug = 1 IF @Debug = 1 PRINT ''''TRACE: Need to pop'''' --need to pop SET @DonePop = 0 WHILE @DonePop = 0 BEGIN SET @StackID = NULL SET @StackDEID = NULL SET @StackTag = NULL SELECT TOP 1 @StackID = StackID, @StackDEID = DEID, @StackTag = CloseTag FROM @tvTagStack ORDER BY StackID DESC SET @DonePop = 1 IF @Debug = 1 IF @Debug = 1 PRINT ''''TRACE: Popped from @CurParentDEID = '''' + ISNULL(CAST(@CurParentDEID AS varchar(100)), ''''NULL'''') + '''' to '''' + ISNULL(CAST(@StackDEID AS varchar(100)), ''''NULL'''') IF @CurParentTag IS NOT NULL BEGIN SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + @CurParentTag END SET @CurParentDEID = @StackDEID SET @CurParentTag = @StackTag --Note: CurParent is left open. May be re-pushed IF @StackID IS NULL BEGIN SET @DonePop = 1 END ELSE BEGIN DELETE FROM @tvTagStack WHERE StackID = @StackID IF ISNULL(@ParentDEID, 0) <> ISNULL(@CurParentDEID, 0) BEGIN SET @DonePop = 0 --render close tag -- SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + @StackTag END END END --WHILE @DonePop = 0 END --IF CurParent change needed IF ISNULL(@ParentDEID, 0) <> ISNULL(@CurParentDEID, 0) BEGIN PRINT ''''Error in DOM: could not pop back to where @ParentDEID = @CurParentDEID '''' + ''''(@ParentDEID = '''' + ISNULL(CAST(@ParentDEID AS varchar(100)), ''''NULL'''') + '''' @CurParentDEID = '''' + ISNULL(CAST(@CurParentDEID AS varchar(100)), ''''NULL'''') + '''')'''' END --#2: Render tag IF @Tag = ''''!--'''' BEGIN --HTML Comment SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + ISNULL(@TextData, '''''''') SET @AllowPush = 0 END ELSE IF @Tag LIKE ''''!%'''' BEGIN --declaration SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + ISNULL(''''<'''' + @TextData + ''''>'''', '''''''') SET @AllowPush = 0 END ELSE IF @Tag IS NULL BEGIN --text node SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + ISNULL(@TextData, '''''''') SET @AllowPush = 0 END ELSE BEGIN --normal node SET @AllowPush = 1 SET @EmitTag = ''''<'''' + @Tag + ISNULL('''' id="'''' + @ID + ''''"'''', '''''''') + ISNULL('''' name="'''' + @Name + ''''"'''', '''''''') + ISNULL('''' class="'''' + @Class + ''''"'''', '''''''') IF EXISTS (SELECT DOMStyleID FROM #tblDOMStyles WHERE DEID = @DEID) BEGIN SET @ThisAttribID = -1 WHILE @ThisAttribID IS NOT NULL BEGIN SET @ThisAttribID = NULL SELECT TOP 1 @ThisAttribID = da.DOMStyleID, @ThisAttribName = da.Name, @ThisAttribValue = da.Value FROM #DOMStyles da WHERE da.DEID = @DEID AND da.DOMStyleID > ISNULL(@LastAttribID, 0) ORDER BY da.DOMStyleID IF @ThisAttribID IS NOT NULL BEGIN SET @ThisStyle = ISNULL(@ThisStyle, '''''''') + ISNULL(@ThisAttribName + '''': '''' + @ThisAttribValue + '''';'''', '''''''') END SET @LastAttribID = @ThisAttribID END END --save list of styles in style attribute EXEC #spupdDOMAttribs @DocID = @DocID OUTPUT, @DEID = @DEID, @Name = ''''style'''', @Value = @ThisStyle IF EXISTS (SELECT DOMAttribID FROM #tblDOMAttribs WHERE DEID = @DEID) BEGIN SET @ThisAttribID = -1 WHILE @ThisAttribID IS NOT NULL BEGIN SET @ThisAttribID = NULL SELECT TOP 1 @ThisAttribID = da.DOMAttribID, @ThisAttribName = da.Name, @ThisAttribValue = da.Value FROM #tblDOMAttribs da WHERE da.DEID = @DEID AND da.DOMAttribID > ISNULL(@LastAttribID, 0) ORDER BY da.DOMAttribID IF @ThisAttribID IS NOT NULL BEGIN SET @EmitTag = @EmitTag + ISNULL('''' '''' + @ThisAttribName + ''''="'''' + @ThisAttribValue + ''''"'''', '''''''') END SET @LastAttribID = @ThisAttribID END END SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + @EmitTag + CASE WHEN @HasChild = 0 THEN ''''/'''' ELSE '''''''' END + ''''>'''' END --#3: Set CurParentDEID = new node, if applicable IF (@AllowPush = 1) AND (@HasChild = 1) BEGIN --push and move CurParent to newly-inserted node IF @CurParentDEID IS NOT NULL BEGIN INSERT INTO @tvTagStack ( DEID, CloseTag ) VALUES ( @CurParentDEID, @CurParentTag ) END IF @Debug = 1 IF @Debug = 1 PRINT ''''TRACE: Push @CurParentDEID = '''' + ISNULL(CAST(@CurParentDEID AS varchar(100)), ''''NULL'''') + '''' New @CurParentDEID = '''' + ISNULL(CAST(@DEID AS varchar(100)), ''''NULL'''') SET @CurParentDEID = @DEID SET @CurParentTag = '''''''' END FETCH curDOM INTO @DEID, @Tag, @ID, @Name, @Class, @TextData, @ParentDEID, @HUID, @DOMLevel, @HasChild END CLOSE curDOM IF @CurParentTag IS NOT NULL BEGIN SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + @CurParentTag END WHILE EXISTS(SELECT StackID FROM @tvTagStack) BEGIN SELECT TOP 1 @StackID = StackID, @StackDEID = DEID, @StackTag = CloseTag FROM @tvTagStack ORDER BY StackID DESC DELETE FROM @tvTagStack WHERE StackID = @StackID SET @RenderedHTML = ISNULL(@RenderedHTML + CASE WHEN @PrettyWhitespace = 1 THEN @CRLF ELSE '''''''' END, '''''''') + ISNULL(@StackTag, '''''''') END SET @HTML = @RenderedHTML DROP TABLE #Render IF @PrintHTML = 1 BEGIN PRINT @HTML END END '') /* ************************************************************************************** PROCEDURE #spactDOMLoad Procedure #spactDOMLoad parses the provided @HTML and loads into DOM. If @ID or @DEID is specified, modifes existing DOM starting with the specified node. If @Selector is specified, the #Load operation will be performed for each node that matches the specified selection. If @ReplaceOuter = 1 the specified node itself will also be replaced (i.e. OUTER HTML), otherwise only the children of the specified node will be replaced (i.e. INNER HTML) If neither @ID or @DEID is specified, clears entire DOM and loads from @HTML. @Attribs may specify a string of Attributes that will be appended to every node affected by #spactDOMLoad. IF @Class is specifed, ************************************************************************************** */ exec('' CREATE PROCEDURE #spactDOMLoad @DocID int = NULL, @HTML varchar(MAX), @ID varchar(512) = NULL, @DEID int = NULL, @ReplaceOuter bit = 0, @CreateNew bit = 0, @Selector varchar(MAX) = NULL, @IncludeAllWhitespace bit = 0, @Tolerate bit = 0 AS BEGIN EXEC #spactDOMOpen @CreateNew = @CreateNew, @DocID = @DocID OUTPUT --local table to hold stack of tags DECLARE @tvTagStack TABLE ( TagStackID int identity PRIMARY KEY , Tag varchar(512), DEID int, ParentDEID int ); DECLARE @tvTargetList TABLE ( DEID int PRIMARY KEY ) DECLARE @TargetDEID int IF @ID IS NOT NULL BEGIN SELECT @DEID = dom.DEID FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.ID = @ID END ELSE IF @Selector IS NOT NULL BEGIN INSERT INTO @tvTargetList (DEID) EXEC #spgetDOM @DocID = @DocID OUTPUT, @Selector = @Selector, @ReturnDEIDsOnly = 1 SELECT TOP 1 @DEID = DEID FROM @tvTargetList END DECLARE @i int DECLARE @c char DECLARE @IsSingleton bit DECLARE @InComment bit DECLARE @InQuote bit DECLARE @StartQuote char DECLARE @ParentDEID int DECLARE @LastDEID int DECLARE @TopStackID int DECLARE @StackTag varchar(8000) DECLARE @PopDone bit DECLARE @State varchar(40) DECLARE @OpenTagName varchar(512) DECLARE @CloseTagName varchar(512) DECLARE @Text varchar(MAX) DECLARE @AttribStr varchar(MAX) DECLARE @CommentStr varchar(MAX) DECLARE @TextChunk varchar(8000) DECLARE @AttribChunk varchar(8000) DECLARE @StartPos int DECLARE @EndPos int DECLARE @CommentStartPos int DECLARE @TextLen int DECLARE @TextChunkLen int DECLARE @DoOpenTag bit DECLARE @DoCloseTag bit DECLARE @ImmediateClose bit IF (@DEID IS NULL) AND (@Selector IS NULL) BEGIN EXEC #spactDOMClear @DocID = @DocID OUTPUT SET @DEID = -1 END WHILE @DEID IS NOT NULL BEGIN SET @Text = '''''''' SET @CommentStr = '''''''' SET @LastDEID = NULL SET @ParentDEID = NULL SET @OpenTagName = NULL SET @CloseTagName = NULL SET @ImmediateClose = 0 SET @IsSingleton = 0 SET @InComment = 0 SET @InQuote = 0 SET @StartQuote = NULL SET @StartPos = NULL SET @EndPos = NULL SET @CommentStartPos = NULL SET @TextChunk = '''''''' SET @AttribChunk = '''''''' SET @Text = '''''''' SET @AttribStr = '''''''' SET @CommentStr = '''''''' SELECT @ParentDEID = CASE WHEN @ReplaceOuter = 1 THEN dom.ParentDEID ELSE dom.DEID END FROM #tblDOM dom WHERE dom.DocID = @DocID AND dom.DEID = @DEID --Note: we are replacing all child nodes. We might be replacing --the target node too--if @ReplaceOuter = 1 IF @HTML IS NOT NULL BEGIN DELETE FROM #tblDOM WHERE (((@ReplaceOuter = 1 ) AND (DEID = @DEID)) OR ((ParentDEID = @DEID) AND (LEFT(@HTML, 1) = ''''<''''))) SET @i = 1 SET @OpenTagName = '''''''' SET @CloseTagName = '''''''' SET @State = ''''Text'''' WHILE @i <= LEN(@HTML) BEGIN SET @c = SUBSTRING(@HTML, @i, 1) --IF @State = ''''Comment'''' BEGIN IF @InComment = 1 BEGIN --special case: locked in processing text until --> SET @CommentStr = @CommentStr + @c IF PATINDEX(''''%-->%'''', @CommentStr) > 0 BEGIN --reached the end of the comment EXEC #spinsDOMNode @DocID = @DocID OUTPUT, @Tag = ''''!--'''', @Text = @CommentStr, @OpenTagStartPos = @CommentStartPos, @CloseTagEndPos = @i, @ParentDEID = @ParentDEID SET @CommentStr = '''''''' SET @CommentStartPos = 0 SET @State = ''''Text'''' SET @InComment = 0 --SET @i = @i + 1 END END ELSE BEGIN IF (@i = LEN(@HTML)) AND ((@IncludeAllWhitespace = 1) OR (@C NOT IN (CHAR(9), CHAR(10), CHAR(13), '''' ''''))) BEGIN --at the last character of our @HTML IF @IncludeAllWhitespace = 1 BEGIN SET @TextLen = LEN(@Text + ''''x'''') - 1 SET @TextChunkLen = LEN(@TextChunk + ''''x'''') - 1 END ELSE BEGIN EXEC #spgetLenNTW @s = @Text, @Len = @TextLen OUTPUT EXEC #spgetLenNTW @s = @TextChunk, @Len = @TextChunkLen OUTPUT END IF (@TextLen > 0) OR (@TextChunkLen > 0) BEGIN --special case of text-only @HTML (no tags) SET @TextChunk = @TextChunk + @c IF @TextChunk <> '''''''' BEGIN SET @Text = @Text + @TextChunk SET @TextChunk = '''''''' END EXEC #spinsDOMNode @DocID = @DocID OUTPUT, @Tag = NULL, @Text = @Text, @ParentDEID = @ParentDEID, @DEID = @LastDEID OUTPUT SET @Text = '''''''' END END --special occurrences of / Note that these could have been coded to --be handled below in each respective State, but seemed more clear to --keep together here. ELSE IF (@c = ''''/'''') AND (@State = ''''StartTag'''') BEGIN SET @State = ''''CloseTagName'''' END ELSE IF (@c = ''''/'''') AND (@State = ''''OpenTagName'''') BEGIN --Immediate close of tag. Actual close will happen on > SET @ImmediateClose = 1 END ELSE IF (@c = ''''/'''') AND (@State = ''''CloseTagName'''') BEGIN --NOOP: we want to drop the / SET @c = @c END ELSE IF (@c = ''''/'''') AND (@State = ''''Attributes'''') AND (@InQuote = 0) BEGIN IF @Tolerate = 1 BEGIN IF SUBSTRING(@HTML, @i + 1, 1) <> ''''>'''' BEGIN --False alarm: HTML is missing quotes around attribute values. --This is not really an indication of the end of the tag. SET @AttribChunk = @AttribChunk + @c IF LEN(@AttribChunk) = 8000 BEGIN SET @AttribStr = @AttribStr + @AttribChunk SET @AttribChunk = '''''''' END END ELSE BEGIN SET @State = ''''OpenTagName'''' SET @ImmediateClose = 1 END END ELSE BEGIN SET @State = ''''OpenTagName'''' SET @ImmediateClose = 1 END END ELSE IF (@c = ''''<'''') BEGIN SET @StartPos = @i IF @TextChunk <> '''''''' BEGIN SET @Text = @Text + @TextChunk SET @TextChunk = '''''''' END IF @Text <> '''''''' BEGIN --reached the end of the text node EXEC #spgetLenNTW @s = @Text, @Len = @TextLen OUTPUT IF ((@IncludeAllWhitespace = 1) OR (@TextLen > 0)) BEGIN EXEC #spinsDOMNode @DocID = @DocID OUTPUT, @Tag = NULL, @Text = @Text, @ParentDEID = @ParentDEID, @DEID = @LastDEID OUTPUT SET @Text = '''''''' END END --See if we are starting a comment IF SUBSTRING(@HTML, @i, LEN('''''''', @IncludeStartTag bit = 1, @IncludeEndTag bit = 1, --Token to mark end of block to return in @ParsedText. NULL means return to end. @ParsedText nvarchar(MAX) = NULL OUTPUT, --Substring of @ResponseText delimeted by @StartTag and @EndTag @ErrorMsg varchar(MAX) = NULL OUTPUT, --NULL unless an error message was encountered @LastResultCode int = NULL OUTPUT, --0 unless an error code was returned by MSXML2.ServerXMLHttp @SuppressResponseText bit = 0, --If 0, actual content is not returned from remote server (just status code) @SuppressResultset bit = 1 --If 0, result set is is not returned (just parameters) AS BEGIN --Retrieves data via HTTP --http://msdn.microsoft.com/en-us/library/aa238861(v=sql.80).aspx SET NOCOUNT ON DECLARE @Debug bit SET @Debug = 0 DECLARE @CRLF char(5) SET @CRLF = CHAR(13) + CHAR(10) DECLARE @XML xml DECLARE @Obj int DECLARE @PerformedInit bit SET @PerformedInit = 0 DECLARE @ErrSource varchar(512) DECLARE @ErrMsg varchar(512) DECLARE @tvResponse TABLE (Response nvarchar(MAX)) BEGIN TRY IF @Debug = 1 PRINT ''''About to call sp_OACreate for MSXML2.ServerXMLHttp'''' EXEC @LastResultCode = sp_OACreate ''''MSXML2.ServerXMLHttp'''', @Obj OUT IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END ELSE BEGIN SET @PerformedInit = 1 END IF @LastResultCode = 0 BEGIN IF @HTTPMethod = ''''GET'''' BEGIN IF @Debug = 1 PRINT ''''About to call sp_OAMethod for open (GET)'''' EXEC @LastResultCode = sp_OAMethod @Obj, ''''open'''', NULL, ''''GET'''', @URL, false IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END END ELSE BEGIN IF @Debug = 1 PRINT ''''About to call sp_OAMethod for open (POST)'''' EXEC @LastResultCode = sp_OAMethod @Obj, ''''open'''', NULL, ''''POST'''', @URL, false IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END IF @Debug = 1 PRINT ''''About to call sp_OAMethod for setRequestHeader'''' IF @LastResultCode = 0 EXEC @LastResultCode = sp_OAMethod @Obj, ''''setRequestHeader'''', NULL, ''''Content-Type'''', @ContentType IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END END END IF @Debug = 1 PRINT ''''About to call sp_OAMethod for send'''' IF @LastResultCode = 0 EXEC @LastResultCode = sp_OAMethod @Obj, ''''send'''', NULL, @DataToSend IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END IF @LastResultCode = 0 EXEC @LastResultCode = sp_OAGetProperty @Obj, ''''status'''', @HTTPStatus OUT IF @LastResultCode <> 0 BEGIN EXEC sp_OAGetErrorInfo @obj, @ErrSource OUTPUT, @ErrMsg OUTPUT PRINT @ErrSource PRINT @ErrMsg END IF (@LastResultCode = 0) AND (ISNULL(@SuppressResponseText, 0) = 0) BEGIN INSERT INTO @tvResponse (Response) EXEC @LastResultCode = sp_OAGetProperty @Obj, ''''responseText'''' --, @Response OUT --Note: sp_OAGetProperty (or any extended stored procedure parameter) does not support --varchar(MAX), however returning as a resultset will return long results. END END TRY BEGIN CATCH SET @ErrorMsg = ERROR_MESSAGE() + ISNULL(@CRLF + @ErrMsg, '''''''') END CATCH BEGIN TRY DECLARE @DestroyResultCode int EXEC @DestroyResultCode = sp_OADestroy @Obj END TRY BEGIN CATCH SET @ErrorMsg = ISNULL(@ErrorMsg + @CRLF, '''''''') + ERROR_MESSAGE() + ''''on call to sp_OADestroy.'''' END CATCH SELECT @ResponseText = Response FROM @tvResponse IF (@LastResultCode = 0) AND (@StartTag IS NOT NULL) BEGIN DECLARE @P1 int DECLARE @P2 int SET @P1 = PATINDEX(''''%'''' + @StartTag +''''%'''', @ResponseText) IF @IncludeEndTag = 0 SET @P1 = @P1 + LEN(@EndTag + ''''x'''') - 1 IF @EndTag IS NULL BEGIN SET @P2 = LEN(@ResponseText + ''''x'''') - 1 END ELSE BEGIN SET @P2 = PATINDEX(''''%'''' + @EndTag + ''''%'''', @ResponseText) - 1 IF @IncludeEndTag = 1 SET @P2 = @P2 + LEN(@EndTag + ''''x'''') - 1 END --SET @ParsedText = REPLACE(tempdb.dbo.RTRIMWhitespace(tempdb.dbo.LTRIMWhitespace(SUBSTRING(@ResponseText, @P1, @P2 - @P1 + 1))), CHAR(9), '''''''') SET @ParsedText = SUBSTRING(@ResponseText, @P1, @P2 - @P1 + 1) EXEC #spactTrimWhitespace @S = @ParsedText OUTPUT, @DoLeft = 1, @DoRight = 1, @TrimTabs = 1 END IF ISNULL(@SuppressResultset, 0) = 0 BEGIN SELECT @URL AS URL, @ResponseText AS ResponseText, @ParsedText AS ParsedText, @HTTPStatus AS HTTPStatus, @LastResultCode AS LastResultCode, @ErrorMsg AS ErrorMsg END IF ((ISNULL(@LastResultCode, -1) <> 0) OR (ISNULL(@DestroyResultCode, -1) <> 0) OR (@ErrorMsg IS NOT NULL)) BEGIN SET @ErrorMsg = ''''Error in #sputlGetHTTP: '''' + @CRLF + ISNULL(NULLIF(RTRIM(@ErrMsg), '''''''') + @CRLF, '''''''') + -- ISNULL(NULLIF(RTRIM(@ErrSource), '''''''') + @CRLF, '''''''') + ISNULL(NULLIF(RTRIM(@ErrorMsg), '''''''') + @CRLF, '''''''') + CASE WHEN @PerformedInit = 0 THEN @CRLF + ''''Remember that this stored procedure uses OLE. To work properly you may need to configure '''' + ''''your database to allow OLE, as follows: '''' + @CRLF + '''' EXEC sp_configure ''''''''show advanced options'''''''', 1;'''' + @CRLF + '''' RECONFIGURE;'''' + @CRLF + '''' EXEC sp_configure ''''''''Ole Automation Procedures'''''''', 1;'''' + @CRLF + '''' RECONFIGURE;'''' + @CRLF + ''''Also, your SQL user must have execute rights to the following stored procedures in master:'''' + @CRLF + '''' sp_OACreate'''' + @CRLF + '''' sp_OAGetProperty'''' + @CRLF + '''' sp_OASetProperty'''' + @CRLF + '''' sp_OAMethod'''' + @CRLF + '''' sp_OAGetErrorInfo'''' + @CRLF + '''' sp_OADestroy'''' + @CRLF + ''''You can grant rights for each of these as follows:'''' + @CRLF + '''' USE master'''' + @CRLF + '''' GRANT EXEC ON sp_OACreate TO myuser'''' + @CRLF + '''' GRANT EXEC etc. ...'''' ELSE '''''''' END RAISERROR(@ErrorMsg, 16, 1) END END '') -------------------- exec('' CREATE PROCEDURE #sputilConvertJSONToXML @JSON nvarchar(MAX), @XML xml OUTPUT AS BEGIN DECLARE @tvStack TABLE ( StackID int IDENTITY PRIMARY KEY, Tag varchar(8000), IsArrayElem bit ) DECLARE @I int DECLARE @C char DECLARE @LastChar char DECLARE @Buf varchar(8000) DECLARE @XMLStr varchar(MAX) DECLARE @Tag varchar(8000) DECLARE @StackID int DECLARE @InQuote bit DECLARE @EndedQuote bit DECLARE @IsArrayElem bit SET @I = 1 SET @InQuote = 0 SET @XMLStr = '''''''' SET @Buf = '''''''' WHILE @I < LEN(@JSON + ''''x'''') - 1 BEGIN IF @C NOT IN (CHAR(9), CHAR(10), CHAR(13), '''' '''') SET @LastChar = @C SET @C = SUBSTRING(@JSON, @I, 1) IF @C = ''''"'''' BEGIN --Found Quote IF @EndedQuote = 1 BEGIN --Just exited a quote: special case for embedded "" SET @Buf = @Buf + @C SET @InQuote = 1 SET @EndedQuote = 0 END ELSE IF @InQuote = 1 BEGIN --We were already in a quote, so we must be exiting SET @InQuote = 0 SET @EndedQuote = 1 END ELSE BEGIN SET @InQuote = 1 END END ELSE BEGIN --not a quote character SET @EndedQuote = 0 IF (@InQuote = 1) BEGIN --just append character IF @C NOT IN (CHAR(9), CHAR(10), CHAR(13)) BEGIN SET @Buf = @Buf + CASE @C WHEN ''''<'''' THEN ''''<'''' WHEN ''''>'''' THEN ''''>'''' WHEN ''''&'''' THEN ''''&'''' ELSE @C END END END ELSE BEGIN --inspect character to determine state IF @C = '''':'''' BEGIN --@Buf contains VarName SET @XMLStr = @XMLStr + ''''<'''' + @Buf + ''''>'''' INSERT INTO @tvStack (Tag) VALUES (@Buf) SET @Buf = '''''''' END ELSE IF @C = '''','''' BEGIN --@Buf contains VarValue IF @Buf <> '''''''' BEGIN SET @XMLStr = @XMLStr + @Buf SET @Buf = '''''''' --pop tag from stack and write closing tag to XML SET @Tag = '''''''' SELECT TOP 1 @Tag = Tag, @StackID = StackID FROM @tvStack ORDER BY StackID DESC DELETE FROM @tvStack WHERE StackID = @StackID IF @Tag <> '''''''' BEGIN SET @XMLStr = @XMLStr + '''''''' END END --We are on a comma. If the top element is an array element, peek and write --a close tag and a re-open tag to XML SET @IsArrayElem = 0 SELECT TOP 1 @IsArrayElem = IsArrayElem, @Tag = Tag FROM @tvStack ORDER BY StackID DESC IF @LastChar = ''''}'''' AND @IsArrayElem = 1 BEGIN SET @XMLStr = @XMLStr + '''''''' + ''''<'''' + @Tag + ''''>'''' END END ELSE IF @C = ''''['''' BEGIN --Start of array. --peek at stack and add first array element tag SET @Tag = '''''''' SELECT TOP 1 @Tag = Tag, @StackID = StackID FROM @tvStack ORDER BY StackID DESC IF @Tag <> '''''''' BEGIN SET @Tag = @Tag + ''''_'''' --push array element tag to stack and write closing tag to XML INSERT INTO @tvStack (Tag, IsArrayElem) VALUES (@Tag, 1) SET @XMLStr = @XMLStr + ''''<'''' + @Tag + ''''>'''' END END ELSE IF @C = ''''}'''' BEGIN --at end of object --pop tag from stack and write closing tag to XML SELECT TOP 1 @Tag = Tag, @StackID = StackID FROM @tvStack ORDER BY StackID DESC DELETE FROM @tvStack WHERE StackID = @StackID IF @Tag <> '''''''' BEGIN SET @XMLStr = @XMLStr + @Buf + '''''''' END SET @Buf = '''''''' END ELSE IF @C = '''']'''' BEGIN SELECT TOP 1 @Tag = Tag, @StackID = StackID FROM @tvStack ORDER BY StackID DESC DELETE FROM @tvStack WHERE StackID = @StackID IF @Tag <> '''''''' BEGIN SET @XMLStr = @XMLStr + @Buf + '''''''' END SET @Buf = '''''''' END ELSE BEGIN IF @C NOT IN (CHAR(9), CHAR(10), CHAR(13), ''''{'''') BEGIN SET @Buf = @Buf + CASE @C WHEN ''''<'''' THEN ''''<'''' WHEN ''''>'''' THEN ''''>'''' WHEN ''''&'''' THEN ''''&'''' WHEN '''' '''' THEN '''''''' ELSE @C END END END END END SET @I = @I + 1 END --pop any remaining tags from stack WHILE EXISTS(SELECT StackID FROM @tvStack) BEGIN SET @Tag = '''''''' SELECT TOP 1 @Tag = Tag, @StackID = StackID FROM @tvStack ORDER BY StackID DESC DELETE FROM @tvStack WHERE StackID = @StackID IF @Tag <> '''''''' BEGIN SET @XMLStr = @XMLStr + '''''''' END END SET @XML = NULLIF(RTRIM(@XMLStr), '''''''') END '') -- ########################## -- ## -- ## END OF RUETER''S CODE -- ## -- ######################################################## -- ########################## -- ## -- ## BEGIN OF NEW UTILS -- ## -- ######################################################## if not object_id(''tempdb..#sputilGetTable '') is null drop proc #sputilGetTable exec('' CREATE PROCEDURE #sputilGetTable @name sysname = null, @DocID int = null, @opt sysname = null, @dbg int = null as begin set nocount on declare @proc sysname,@ret int select @proc=''''#sputilGetTable'''', @dbg=isnull(@dbg,0),@docid=isnull(@docid,1) if @name is null goto help ;WITH DOMTree ( DEID, DocID, Tag, ID, Name, Class, TextData, OpenTagStartPos, CloseTagEndPos, ParentDEID, HUID, SortHUID, DOMLevel ) AS ( SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS HUID, CAST(RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, 1 AS DOMLevel FROM #tblDOM dom WHERE -- dom.ParentDEID IS NULL dom.DEID=(select DEID from #tblDOM where tag=''''table'''' and isnull(id,'''''''')=@name) UNION ALL SELECT dom.DEID, dom.DocID, dom.Tag, dom.ID, dom.Name, dom.Class, dom.TextData, dom.OpenTagStartPos, dom.CloseTagEndPos, dom.ParentDEID, CAST(domch.HUID + ''''.'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)) AS varchar(900)) AS HUID, CAST(domch.SortHUID + ''''.'''' + RIGHT(''''000000'''' + CAST(ROW_NUMBER() OVER (ORDER BY dom.DEID) AS varchar(900)), 6) AS varchar(900)) AS SortHUID, domch.DOMLevel + 1 FROM DOMTree domch JOIN #tblDOM dom ON domch.DEID = dom.ParentDEID ) --CTE End ----------------------- SELECT * INTO #xtable FROM DOMTree dom WHERE dom.DocID = @DocID ORDER BY dom.SortHUID if @dbg=2 select * from #xtable -- extract table declare @sql nvarchar(max),@crlf varchar(2) select @crlf=crlf from fn__sym() select top 100 @sql=isnull(@sql+'''','''','''''''')+ -- ''''[''''+textdata+''''] nvarchar(4000)''''+@crlf ''''(select top 1 TextData from #xtable ''''+ '''' where huid like t.huid+''''''''.''''+ cast((row_number() over (order by huid)) as varchar(5))+ ''''.%'''''''' and tag is null''''+ '''') [''''+TextData+'''']''''+@crlf -- select huid,textdata from #xtable where huid like ( select top 1 huid from #xtable where tag in(''''tr'''') order by sorthuid )+''''.%'''' and tag is null order by sorthuid -- select @sql=''''create table [''''+@name+''''](''''+@crlf+@sql+'''')''''+@crlf select @sql=''''select''''+@crlf+@sql +''''from ( select huid from #xtable t where t.tag=''''''''tr'''''''' and huid!=''''''''1.1.1'''''''' ) t '''' if @dbg=1 exec sp__printsql @sql exec(@sql) goto ret help: exec sp__usage @proc,'''' Scope return content table of html table @name Notes Use #spgetDOM @selector="table" to list tables Parameters @name name of table @DocID default 1 '''' ret: return 0 end '') if @err!=0 or @dbg>0 begin exec sp__printf ''-- web tools installed'' exec sp__select_astext '' select left(name,charindex(''''_'''',name)-1) web_proc from tempdb..sysobjects where name like ''''#sp%'''' '',@header=1 end end -- install option goto ret -- =================================================================== errors == /* err_sample1: exec @ret=sp__err ''code "%s" not exists'',@proc,@p1=@param goto ret */ -- ===================================================================== help == help: exec sp__usage @proc,'' Scope enable a set of #sp to download data from web and explore DOM. Notes this SP encapsulate code of David Rueter, taken from http://sourceforge.net/projects/sqldom/files/ Follow this steps 1. open SQLDOM_core_XXX.sql 2. replace all single quote with two single quotes 3. move examples after last GO below 4. put CREATE of #DOM tables into IF not OBJECT_ID(''''... and copy tables definitions here 6. replaces GO with EXEC(...) 7. done Tables CREATE TABLE #tblDOMDocs( DocID int identity PRIMARY KEY, DateCreated datetime, DocName varchar(128) ) /* ************************************************************************************** TABLE #tblDOM Table #tblDOM is for internal representation of the DOM data ************************************************************************************** */ CREATE TABLE #tblDOM ( DEID int identity PRIMARY KEY, DocID int, Tag varchar(MAX), ID varchar(512), Name varchar(512), Class varchar(512), TextData varchar(MAX), OpenTagStartPos int, CloseTagEndPos int, ParentDEID int ) CREATE INDEX ixDOMTable_ParentDEID ON #tblDOM (ParentDEID) INCLUDE (DEID, DocID) CREATE INDEX ixDOMTable_DEID ON #tblDOM (DEID, DocID) --NOTE: SQL 2008 introduced filtered indexes, which makes it easy to enforce --unqique-but-nullable. If on SQL 2008 or greater AND you wish to enforce uniqueness --of ID and Name attributes, uncomment the following two lines -- CREATE UNIQUE INDEX tmpixDOMTable_ID ON #tblDOM (ID) INCLUDE (DEID) WHERE ID IS NOT NULL -- CREATE UNIQUE INDEX tmpixDOMTable_Name ON #tblDOM (Name) INCLUDE (DEID) WHERE Name IS NOT NULL /* Note: TextData will contain the data for the first text node (if any) under the tag. Subsequent text nodes (if any) will be in their own #tblDOM row, with a null TAG and referencing the original DEID in the ParentDEID column. */ /* ************************************************************************************** TABLE #DOMAttribs Table #tblDOMAttribs is for internal representation of the DOM data--specifically, for attributes of DOM elements ************************************************************************************** */ CREATE TABLE #tblDOMAttribs( DOMAttribID int identity PRIMARY KEY, DEID int, Name varchar(512), Value varchar(MAX) ) CREATE UNIQUE INDEX uqDOMAttribs_DEID ON #tblDOMAttribs (DEID, Name) CREATE INDEX ixDOMAttribs_DEID ON #tblDOMAttribs (DEID) INCLUDE (Name, Value) /* ************************************************************************************** TABLE #tblDOMStyles Table #tblDOMAttribs is for internal representation of the DOM data--specifically, for attributes of DOM elements ************************************************************************************** */ CREATE TABLE #tblDOMStyles( DOMStyleID int identity PRIMARY KEY, DEID int, Name varchar(512), Value varchar(MAX) ) CREATE UNIQUE INDEX ixDOMStyles_ID ON #tblDOMStyles (DEID, Name) CREATE INDEX ixDOMStyles_DEID ON #tblDOMStyles (DEID) INCLUDE (Name, Value) Parameters @opt options install add web procedures uninstall drop web procedures keep preserve tables otherwise install will drop #dom... @dbg 1 show installed #sp See sp__html_table Examples Things to try: --Example 1: Simple parse of string EXEC #spactDOMLoad @HTML = ''''Hello World.

SQLDOM ROCKS!

'''' EXEC #spgetDOM --Example 2: Render HTML from DOM (that we parsed in Example 1 above) EXEC #spgetDOMHTML @PrettyWhitespace=1, @PrintHTML = 1 --Example 3: Parse and re-render from a URL DECLARE @HTML varchar(MAX) EXEC #sputilGetHTTP @URL = ''''http://www.google.com'''', @ResponseText = @HTML OUTPUT, @SuppressResultset = 1 EXEC #spactDOMLoad @HTML=@HTML EXEC #spgetDOM EXEC #spgetDOMHTML @PrettyWhitespace=1, @PrintHTML = 1 --Example 4: Parse from a string, modify the DOM, render resulting HTML EXEC #spactDOMLoad @HTML = ''''Hello World.
Future content goes here
'''' EXEC #spactDOMLoad @HTML = ''''
Here is some neat stuff about SQLDOM
'''', @Selector = ''''.myContent'''' EXEC #spgetDOM EXEC #spgetDOMHTML @PrettyWhitespace=1, @PrintHTML = 1 '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__web_tool' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__web_tool: -- ============================================================= sp__web_ws_test select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__web_ws_test',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=121017 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__web_ws_test') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__web_ws_test') with nowait goto skip_sp__web_ws_test end if @ver>121017 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__web_ws_test') with nowait goto skip_sp__web_ws_test end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__web_ws_test') with nowait if exists( select top 1 null from sys.objects where name='sp__web_ws_test' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__web_ws_test] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,test r:121017\s.zaglio: adapted sp__web_ws to null prev bugs r:121016\s.zaglio: bug near N'' and crlf r:121015\s.zaglio: test sp__web_ws t:sp__web_ws_test @opt=''run'',@dbg=1 */ CREATE proc sp__web_ws_test @tst sysname = null, @opt sysname = null, @dbg int=0 as begin -- set nocount on added to prevent extra result sets from -- interferring with select statements. -- and resolve a wrong error when called remotelly set nocount on -- @@nestlevel is >1 if called by other sp declare @proc sysname, @err int, @ret int, -- @ret: 0=OK -1=HELP, any=error id -- error vars @e_msg nvarchar(4000), -- message error @e_opt nvarchar(4000), -- error option @e_p1 sql_variant, @e_p2 sql_variant, @e_p3 sql_variant, @e_p4 sql_variant select @proc=object_name(@@procid), @err=0, @ret=0, @dbg=isnull(@dbg,0), -- is the verbosity level @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') -- ========================================================= param formal chk == -- ============================================================== declaration == declare -- generic common -- @i int,@n int, -- index, counter -- @sql nvarchar(max), -- dynamic sql -- options -- @opt1 bit,@opt2 bit, @crlf nvarchar(2), @response nvarchar(max), @status nvarchar(4000), @url nvarchar(1024), @sa nvarchar(1024), @end_declare bit -- =========================================================== initialization == select -- @opt1=charindex(''|opt|'',@opt), @crlf=crlf, @tst=isnull(@tst,''''), @end_declare=1 from fn__sym() -- ======================================================== second params chk == if @tst='''' goto help if @tst=''all'' select @tst=''0'' if isnumeric(@tst)=0 goto err_tst if @tst<0 or @tst>4 goto err_tst -- ===================================================================== body == -- sp__web_ws_test run,@dbg=1 if @tst in (0,1) begin exec sp__prints ''simple url get'' select @url=''http://www.webservicex.com/stockquote.asmx/GetQuote?symbol=MSFT'' exec @ret=sp__web @url,@rsp=@response out,@sts=@status out,@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''status=%s'',@status end if @tst in (0,2) begin exec sp__prints ''not exists test'' select @url=''http://www.thisdonotexist.exw/i.html'' exec @ret=sp__web @url,@dbg=@dbg exec sp__printf ''@ret:%d'',@ret exec sp__prints ''bad method'' select @url=''http://www.webservicex.com/stockquote.asmx/GetQuote?symbol=MSFT'' exec @ret=sp__web @url,''got'',@dbg=@dbg exec sp__printf ''@ret:%d'',@ret end -- sp__web_ws_test 3,@dbg=1 if @tst in (0,3) begin exec sp__prints ''web service'' select @url=''http://www.webservicex.net/globalweather.asmx'' exec @ret=sp__web @url, @rsp=@response out, @sa=''http://www.webserviceX.NET/GetWeather'', @rcq='' brescia italy '',@sts=@status out,@dbg=@dbg --,@opt=''nodecode'' if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''status=%s'',@status end -- sp__web_ws_test 4,@dbg=1 if @tst in (0,4) begin exec sp__prints ''smart SOAP call'' create table #rcqprms( id int identity, rid int default(0), var nvarchar(500), val nvarchar(max) ) insert #rcqprms(var,val) select ''CityName'',''brescia'' insert #rcqprms(var,val) select ''CountryName'',''italy'' select @url=''http://www.webserviceX.NET/globalweather.asmx'', @sa =''GetWeather'' exec @ret=sp__web @uri=@url, @sa=@sa,@sts=@status out,@rsp=@response out ,@dbg=@dbg if @ret in (0,-176288843) exec sp__printsql @response else exec sp__printf ''status=%s'',@status drop table #rcqprms end -- soap smart call -- ================================================================== dispose == dispose: -- drop temp tables, flush data, etc. goto ret -- =================================================================== errors == err: exec @ret=sp__err @e_msg,@proc,@p1=@e_p1,@p2=@e_p2,@p3=@e_p3, @p4=@e_p4,@opt=@e_opt goto ret err_tst: select @e_msg=''wrong @tst value'' goto err -- ===================================================================== help == help: exec sp__usage @proc,'' Scope test the sp__web_ws: 1. simple test (get a url) 2. wrong test (bad url) 3. wrong method (got instead of get) Parameters @tst id of specific test 1 test simple get 2 test wrong params 3 test SOAP call 4 test SOAP smart call ALL all above '' select @ret=-1 -- ===================================================================== exit == ret: return @ret end -- proc sp__web_ws_test' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__web_ws_test: -- ==================================================================== sp__wiki select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__wiki',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110316 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__wiki') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__wiki') with nowait goto skip_sp__wiki end if @ver>110316 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__wiki') with nowait goto skip_sp__wiki end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__wiki') with nowait if exists( select top 1 null from sys.objects where name='sp__wiki' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__wiki] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110316\s.zaglio: a small adapt to new #blob managment v:100514\s.zaglio: added code for automanual (see help) v:100424\s.zaglio: some small bugs v:100405\s.zaglio: added *new+* v:100328\s.zaglio: added special *img* tag v:100221\s.zaglio: interpret the @txt and write down into #src a coded document */ CREATE proc [dbo].[sp__wiki] @txt nvarchar(4000)=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=''sp__wiki'',@ret=0 if @txt is null goto help declare @buffer nvarchar(4000),@crlf nvarchar(2),@crlf_len int, @n int,@i int,@line nvarchar(4000),@p int,@lno int, @code bit,@j int,@sum_pos int,@token sysname, @lp sysname,@rp sysname,@title sysname, @ptr binary(16),@lbegin int,@lend int if not object_id(@txt) is null begin create table #blob(id int identity,blob ntext) insert #blob(blob) select '''' select top 1 @ptr=textptr(blob) from #blob where id=1 declare cs cursor local for select ctext from syscomments where id=object_id(@txt) order by colid open cs while 1=1 begin fetch next from cs into @line if @@fetch_status!=0 break updatetext #blob.blob @ptr null null @line end close cs deallocate cs exec sp__write_ntext_to_lines @crlf=0 -- split blob into lines, removing end crlf select top 1 @lbegin=lno from #src where ltrim(rtrim(line)) in (''/*wiki'',''/* wiki'') order by lno select top 1 @lend =lno from #src where ltrim(rtrim(line)) in (''wiki*/'',''wiki */'') order by lno desc delete from #src where lno<=@lbegin or lno>=@lend drop table #blob goto ret end -- automanual create table #summary(lno int, lev int, line nvarchar(4000)) create table #tmp (lno int identity(10,10),line nvarchar(4000)) declare cs cursor local for select lno,line from #src order by lno select @crlf=dbo.fn__crlf(),@crlf_len=len(@crlf) -- remove 1st crlf if left(@txt,@crlf_len)=@crlf select @txt=substring(@txt,@crlf_len,4000) -- adjust crlf (mssql editor fakes) select @txt=replace(@txt,@crlf,char(13)) select @txt=replace(@txt,char(10),char(13)) if @dbg=1 exec sp__printf ''----------------------------------\n%s'',@txt if not left(@txt,2) in (''[#'',''[:'') begin -- split to more lines select @n=dbo.fn__str_count(@txt,char(13)) select @i=1 while (@i<=@n) begin select @line=dbo.fn__str_at(@txt,char(13),@i) insert #src select rtrim(@line) select @i=@i+1 end end else begin if @txt in (''[:print:]'',''[:print.text:]'') exec sp__print_table ''#src'' if @txt in (''[:print.html:]'') begin -- find summary position select @sum_pos=lno from #src where line=''[:summary:]'' -- add end of line update #src set line=replace(line,char(13),''
''+@crlf) if @@error!=0 exec sp__printf ''%s'',''!# error adding end of line'' -- generate summary insert into #summary select lno,0,line from #src where lno>@sum_pos and left(line,1)=''+'' if @@error!=0 exec sp__printf ''%s'',''!# error generating summary(0)'' update #summary set lev=3,line=substring(line,4,4000) where left(line,3)=''+++'' if @@error!=0 exec sp__printf ''%s'',''!# error generating summary(1)'' update #summary set lev=2,line=substring(line,3,4000) where left(line,2)=''++'' if @@error!=0 exec sp__printf ''%s'',''!# error generating summary(2)'' update #summary set lev=1,line=substring(line,2,4000) where left(line,1)=''+'' if @@error!=0 exec sp__printf ''%s'',''!# error generating summary(3)'' -- add titles update #src set line=''

''+substring(line,4,4000)+''

'' where left(line,3)=''+++'' if @@error!=0 exec sp__printf ''%s'',''!# error adding titles (1)'' update #src set line=''

''+substring(line,3,4000)+''

'' where left(line,2)=''++'' if @@error!=0 exec sp__printf ''%s'',''!# error adding titles (2)'' update #src set line=''

''+substring(line,2,4000)+''

'' where left(line,1)=''+'' if @@error!=0 exec sp__printf ''%s'',''!# error adding titles (3)'' -- special replacer update #src set line=replace(line,''*new*'',''New Icon''+@crlf) if @@error!=0 exec sp__printf ''%s'',''!# error in special replacer(1)'' update #src set line=replace(line,''*new+*'',''New Icon''+@crlf) if @@error!=0 exec sp__printf ''%s'',''!# error in special replacer(2)'' -- add bold select @code=0 open cs while 1=1 begin fetch next from cs into @lno,@line if @@fetch_status!=0 break /* select @i=1,@l=len(@line),@ while (@i<=@l) begin select @c=substring(@line,@i,1) if @c=''['' select @token=@token+@c if @rule=0 and @c=''*'' select @rule= */ select @token=''[:code:'' select @p=charindex(@token,@line) if @p>0 select @line=left(@line,@p-1)+''
''
                            +substring(@line,@p+len(@token),4000),
                       @code=1

            -- select @code=@code+dbo.fn__occurrence(@line,''['')
            if @code>0 and left(ltrim(@line),1)='']''
                begin
                select @p=dbo.fn__charindex('']'',@line,-1)
                if @p>0 select @line=left(@line,@p-1)+''
'' +substring(@line,@p+1,4000), @code=0 /* select @p=0 if @code-dbo.fn__occurrence(@line,'']'')=1 */ end select @lp=''%*[A-z,0-9]%'',@rp=''%[.,A-z,0-9]*%'' select @p=patindex(@lp,@line) -- print patindex(''%*[A-z,0-9]%'',''*test line'') -- print patindex(''%*[A-z,0-9]%'',''* test line'') -- print patindex(''%*[A-z,0-9]%'',''test)* line'') while (@p>0) begin select @line=left(@line,@p-1)+''''+substring(@line,@p+1,4000) select @p=patindex(@lp,@line) end -- print patindex(''%[.,A-z,0-9]*%'',''test line.*'') select @p=patindex(@rp,@line) while (@p>0) begin select @line=left(@line,@p)+''''+substring(@line,@p+1,4000) select @p=patindex(@rp,@line) end update #src set line=@line where lno=@lno if @@error!=0 exec sp__printf ''!# error updating\n%s'',@line end -- lines close cs -- replace summary select @n=count(*) from #summary if not @sum_pos is null and @n>0 begin truncate table #tmp insert #tmp select line from #src where lno<@sum_pos order by lno insert #tmp select replicate('' '',lev)+''''+line+'''' from #summary if @@error!=0 exec sp__printf ''%s'',''!# error updating summary (1)'' insert #tmp select line from #src where lno>@sum_pos order by lno if @@error!=0 exec sp__printf ''%s'',''!# error updating summary (2)'' end -- summary truncate table #src insert #src select line from #tmp order by lno -- incapsulate into html and print select line from ( select -100 lno,'''' line union select -099 lno,'''' line union -- from: http://shjs.sourceforge.net/doc/documentation.html -- or: http://softwaremaniacs.org/media/soft/highlight/test.html select -098 lno,'''' line union select -097 lno,'''' line union select -096 lno,'''' line union select -095 lno,'''' line union select -094 lno,'''' line union select -093 lno,''
'' line union
        select lno,line from #src union
        select 1E10 lno,''
'' line union select 2E20 lno,'''' line ) ssrc order by lno end -- if @txt in (''[:print.html:]'') end -- left(@txt,2) in (''[#'',''[:'') deallocate cs goto ret help: exec sp__usage @proc,'' Parameters @txt is the text to add to #src if exist an object with name @txt, the source will be scanned to find a block between "/*wiki" and "wiki*/" So to write an sp with automanual: create table #src(lno int identity,line nvarchar(4000)) exec sp__wiki @proc -- myself exec sp__wiki ''''[:print.text]'''' drop table #src /*wiki .... wiki*/ Wiki rules * a crlf keep the paragraph rogether * a "."+crlf become a
* 1st crlf in @txt is removed * a "."+space+crlf become a single paragraph * [:lng.XXX: ... ] set syntax highligher for this language * [:print:],[:print.text:] compile the doc and print it as text * [:print.html:] compile and print with html tags '' ret: return @ret end -- sp__wiki' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__wiki: -- ===================================================== sp__write_ntext_to_file select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__write_ntext_to_file',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=101109 begin if @aut!='m.stefanoni' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__write_ntext_to_file') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__write_ntext_to_file') with nowait goto skip_sp__write_ntext_to_file end if @ver>101109 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__write_ntext_to_file') with nowait goto skip_sp__write_ntext_to_file end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__write_ntext_to_file') with nowait if exists( select top 1 null from sys.objects where name='sp__write_ntext_to_file' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__write_ntext_to_file] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:101109\m.stefanoni: corretto perchè non andava bene il bcp.fmt in c v:101105\m.stefanoni: in bcp command line has been added a format file to avoid the 4-byte prefix in generated file v:100202\m.stefanoni: removed "use db_name(); " from bcp parameters for sql 2005 compatibility v:091210\s.zaglio: added specific tests v:091126\s.zaglio: to ncode v:091120\s.zaglio: added @uid/@pwd that if nulls -> trusted connection v:091119\s.zaglio: restyle and adde @dbg & error managment & help v:090721\m.stefanoni:cleaned up v:080807\m.stefanoni:changed to bcp v:080806\m.stefanoni:creation t: sp__write_ntext_to_file ''select top 1 im_file_content from [srvsin01-it]..rep07_files where not im_file_content is null'',''%temp%\test.tst'', @dbg=1 exec sp__run_cmd ''dir "%temp%\*.tst" & del "%temp%\test.tst"'' */ CREATE procedure [sp__write_ntext_to_file] @sqlfield nvarchar(4000)=null, @file nvarchar(400)=null, @uid sysname=null, @pwd sysname=null, @dbg bit=0 as begin set nocount on declare @ret int,@proc sysname select @ret=0,@proc=''sp__write_ntext_to_file'' if @sqlfield is null or @file is null or charindex(''*'', @file)>0 or charindex(''?'', @file) > 0 goto help select @sqlfield=replace(@sqlfield,char(13),'''') select @sqlfield=replace(@sqlfield,char(10),'''') declare @cmd nvarchar(4000) -- generica per la xp_cmdshell declare @format_file nvarchar(400) DECLARE @temp_dir nvarchar(256) EXEC sp__get_temp_dir @temp_dir OUT SET @cmd = ''echo 9.0 > "'' + @temp_dir + ''\bcp.fmt"'' exec master..xp_cmdshell @cmd, NO_OUTPUT SET @cmd = ''echo 1 >> "'' + @temp_dir + ''\bcp.fmt"'' exec master..xp_cmdshell @cmd, NO_OUTPUT SET @cmd = ''echo 1 SQLBINARY 0 0 "" 1 data "" >> "'' + @temp_dir + ''\bcp.fmt"'' exec master..xp_cmdshell @cmd, NO_OUTPUT -- sp__run_cmd ''bcp'' -- print dbo.fn__servername(null) set @cmd = ''@bcp "'' + @sqlfield + ''" queryout "'' + @file + ''" -S '' + dbo.fn__servername(null) + '' -F 1 -L 1 -n -f "'' + @temp_dir + ''\bcp.fmt" '' if @uid is null and @pwd is null select @cmd=@cmd+''-T '' else select @cmd=@cmd+''-U ''+@uid+'' -P ''+coalesce(@pwd,'''')+'' '' if @dbg=1 exec sp__printf @cmd create table #src (lno int identity(10,10),line nvarchar(4000)) insert into #src(line) exec @ret=master..xp_cmdshell @cmd if @ret=0 and exists(select null from #src where line like ''Error = %'') select @ret=1 if @dbg=1 exec sp__print_table ''#src'' drop table #src return @ret help: select @cmd =''Usage:\n'' +''\t@sqlfield is the sql code that return a text/image field\n'' +''\t@file is the name of destination file'' +''\t@file cannot contain wild card'' exec sp__usage @proc,@cmd return -1 end -- proc' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__write_ntext_to_file: -- ==================================================== sp__write_ntext_to_lines select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__write_ntext_to_lines',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=110509 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__write_ntext_to_lines') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__write_ntext_to_lines') with nowait goto skip_sp__write_ntext_to_lines end if @ver>110509 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__write_ntext_to_lines') with nowait goto skip_sp__write_ntext_to_lines end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__write_ntext_to_lines') with nowait if exists( select top 1 null from sys.objects where name='sp__write_ntext_to_lines' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__write_ntext_to_lines] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility v:110509\s.zaglio: a bug near last line without crlf v:110329\s.zaglio: added @nosrc v:110316\s.zaglio: added multi blob management v:100919\s.zaglio: managed empty #blob v:100515\s.zaglio: added @crlf to remove line terminator v:100514\s.zaglio: rewritten t: create table #src(lno int identity(10,10),line nvarchar(4000)) exec sp__write_ntext_to_lines ''select blob from gamon.ramses.dbo.SETUP0H_WIKIDOCS where id=971'' exec sp__print_table ''#src'' drop table #src */ CREATE proc [dbo].[sp__write_ntext_to_lines] @sqlfield nvarchar(4000)=null, @crlf bit=1, @nosrc bit=0, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0 if @sqlfield is null and object_id(''tempdb..#blob'') is null goto help declare @drop bit, @n int,@i int,@p int,@j int,@id int, @ncrlf nvarchar(2),@cr nchar(1),@lf nchar(1), @lcrlf int declare @lines table (pos int primary key,leng int) select @dbg=isnull(@dbg,0),@crlf=isnull(@crlf,1),@nosrc=isnull(@nosrc,0) if object_id(''tempdb..#blob'') is null begin create table #blob(blob ntext) exec(''insert #blob ''+@sqlfield) select @drop=1 end else select @drop=0 select @ncrlf=crlf,@cr=cr,@lf=lf,@lcrlf=len(crlf) from dbo.fn__sym() declare cs cursor local for select id from #blob where 1=1 open cs while 1=1 begin fetch next from cs into @id if @@fetch_status!=0 break delete from @lines -- identify row separator select top 1 @i=charindex(@cr,blob),@j=charindex(@lf,blob) from #blob b where b.id=@id if @i is null begin select @ret=-2 goto ret end if @i>0 and @j=0 select @ncrlf=@cr if @i=0 and @j>0 select @ncrlf=@lf if @i=@j+1 select @ncrlf=@lf+@cr -- else is @ncrlf select top 1 @i=1,@p=1,@j=1,@n=datalength(blob)/2 from #blob where id=@id if @dbg=1 exec sp__printf ''i=%d,n=%d,id=%d'',@i,@n,@id while 1=1 begin select top 1 @i=charindex(@ncrlf,substring(blob,@j,4000)) from #blob b where b.id=@id if @i=0 begin -- last pieces that do not end with crlf -- if @dbg=1 exec sp__printf ''j:%d, i:%d, @n:%d'',@j,@i,@n if @n>@j/*+@lcrlf*/-1 insert @lines select @j,@n-@j+1 break end -- if @dbg=1 exec sp__printf ''j:%d, i:%d'',@j,@i if @crlf=1 or @i-@lcrlf+1<0 insert @lines select @j,@i else insert @lines select @j,@i-@lcrlf+1 select @j=@j+@i+@lcrlf-1 end -- while if @dbg=1 begin select pos,leng,substring(blob,pos,leng) line from #blob b,@lines where b.id=@id order by pos desc end else begin if object_id(''tempdb..#src'') is null or @nosrc=1 select substring(blob,pos,leng) line from #blob b,@lines where b.id=@id order by pos else insert into #src select substring(blob,pos,leng) line from #blob b,@lines where b.id=@id order by pos end end -- while of cursor close cs deallocate cs if @drop=1 drop table #blob goto ret help: exec sp__usage @proc,'' Scope explode blobs into lines Params: @sqlfiled must be a query that return a text/ntext field or can be null but must exists #blob @crlf (default 1) leave line terminator; 0 remove it @nosrc ignore #src and out to stdout to insert into @src etc. create table #blob(id int identity,blob ntext) create table #src(lno int identity(10,10),line nvarchar(4000)) '' select @ret=-1 ret: return @ret end -- proc sp__write_ntext_to_lines' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__write_ntext_to_lines: -- ============================================================== sp__xls_attach select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__xls_attach',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=130906 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__xls_attach') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__xls_attach') with nowait goto skip_sp__xls_attach end if @ver>130906 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__xls_attach') with nowait goto skip_sp__xls_attach end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__xls_attach') with nowait if exists( select top 1 null from sys.objects where name='sp__xls_attach' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__xls_attach] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,xls v:130906\s.zaglio: adapted to fn__parse_url rename v:130217\s.zaglio: added resources into help and q option r:120314\s.zaglio: adapted to sql2k5 (32&64bit) v:100508\s.zaglio: removed convertion, used imex v:100501\s.zaglio: skip print/area/filters..and not real sheets; added imex and @nohd v:100424\s.zaglio: create views for xls files t:sp__xls_attach ''c:\shared_folders\backup_db\'',''xls_tests'' ,@dbg=1 t:sp__dir ''xls*'' -- sp__drop ''xls_tests_*'',@simul=0 */ CREATE proc [dbo].[sp__xls_attach] @path nvarchar(512)=null, @root sysname=null, @opt sysname=null, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=object_name(@@procid),@ret=0, @opt=dbo.fn__str_quote(isnull(@opt,''''),''|'') if @path is null goto help -- ================================================================== declare == declare @cmd nvarchar(1024), @file nvarchar(512), @tbl sysname,@i int,@n bigint, @sql nvarchar(4000),@view sysname, @flds nvarchar(4000),@psep nchar(1), @crlf nvarchar(2),@tmp sysname,@obj sysname, @quiet bit create table #xls(id int identity,[file] nvarchar(4000)) create table #tbls( id int identity, table_cat sysname null, table_schem sysname null, table_name sysname null, table_type sysname null, remarks sysname null, view_name sysname null ) create table #providers( cod sysname, parse sysname, des sysname ) -- ===================================================================== init == select @quiet=charindex(''|q|'',@opt)|charindex(''|quiet|'',@opt), @psep=psep, @crlf=crlf from dbo.fn__sym() if not right(@path,4)=''.xls'' and not right(@path,5)=''.xlsx'' begin if right(@path,1)!=''\'' select @path=@path+''\'' select @path=@path+''*.xls?'' end -- xp_cmdshell ''dir /b "d:\sapshare\xls_seltris\*.xls"'' select @cmd=''dir /s /b "''+@path+''"'' -- drop table #stdout -- ===================================================================== body == -- check providers insert #providers exec xp_enum_oledb_providers if not exists( select cod from #providers where cod in (''MSDASQL'',''Microsoft.ACE.OLEDB.12.0'') ) goto err_prv -- OLEDB Provider for ODBC (MSDASQL) if @dbg=1 exec sp__printf''path=%s'',@path insert #xls exec xp_cmdshell @cmd delete from #xls where [file] is null -- last null row select @n=max(id) from #xls if @n is null goto err_nof declare cs cursor local for select [file] from #xls where 1=1 open cs while 1=1 begin fetch next from cs into @file if @@fetch_status!=0 break if @quiet=0 exec sp__printf ''-- link file %s'',@file -- some sheet shave wrong cells other not work if exists(select null from master..sysservers where srvname=''$xls'') exec master.dbo.sp_dropserver @server=N''$xls'', @droplogins=''droplogins'' -- declare @file sysname,@tmp sysname select @file=''c:\shared_folders\backup_db\sqltest.xlsx'' select @tmp=''xls_''+replace(convert(sysname,newid()),''-'',''_'') exec sp_addlinkedserver @server = @tmp, @srvproduct=''xls'', @provider=''microsoft.ace.oledb.12.0'', @datasrc=@file, @provstr=''excel 12.0;readonly=1'' -- sp__xls_attach ''c:\backup'' declare @su sysname select @su=system_user exec sp_addlinkedsrvlogin @tmp, ''false'', @su, N''ADMIN'', NULL truncate table #tbls insert #tbls(table_cat,table_schem,table_name,table_type,remarks) exec master.dbo.sp_tables_ex @table_server = @tmp -- select * from #tbls if @dbg=0 exec master.dbo.sp_dropserver @server=@tmp, @droplogins=''droplogins'' if @dbg=1 exec sp__select_astext ''#tbls'',@header=1 -- declare @file sysname,@root sysname select @file=''c:\shared_folders\backup_db\sqltest.xlsx'' if @root is null update #tbls set view_name=''xls_''+replace(dbo.fn__format(@file,''AN'',default),''__'',''_'')+ ''_''+table_name from #tbls else begin select @root+''_''+dbo.fn__format(page,''AN'',default)+''_''+table_name from #tbls,dbo.fn__parse_url(''file:///''+@file,default) update #tbls set view_name=@root+''_''+dbo.fn__format(page,''AN'',default)+''_''+table_name from #tbls,dbo.fn__parse_url(''file:///''+@file,default) end -- strip last dollar update #tbls set view_name=left(view_name,len(view_name)-1) where right(view_name,1)=''$'' -- create view for sheets with data declare sh cursor local for select table_name,quotename(view_name) from #tbls where right(table_name,1)=''$'' -- skip subsheets/view/filters/print areas... open sh while 1=1 begin fetch next from sh into @tmp,@obj if @@fetch_status!=0 break select @sql=''select @n=count(*) from openrowset(''''MSDASQL'''',''+ ''''''DRIVER=Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb);''+ ''UID=admin;UserCommitSync=Yes;Threads=3;SafeTransactions=0;ReadOnly=1;''+ ''PageTimeout=5;MaxScanRows=8;MaxBufferSize=2048;FIL=excel 14.0;DriverId=1046;''+ ''DBQ=''+@file+'''''',''''''+ '' select top 1 * from [''+@file+''].[''+@tmp+'']'''')'' select @n=null if @dbg=1 exec sp__printsql @sql exec sp_executesql @sql,N''@n bigint out'',@n=@n out if isnull(@n,0)>0 begin if not object_id(@obj) is null exec(''drop view ''+@obj) select @sql= ''create view ''+@obj+'' as ''+ ''select * from openrowset(''''MSDASQL'''',''+ ''''''DRIVER=Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb);''+ ''UID=admin;UserCommitSync=Yes;Threads=3;SafeTransactions=0;ReadOnly=1;''+ ''PageTimeout=5;MaxScanRows=8;MaxBufferSize=2048;FIL=excel 14.0;DriverId=1046;''+ ''DBQ=''+@file+'''''',''''''+ '' select * from [''+@file+''].[''+@tmp+'']'''')'' exec(@sql) end end -- while of cursor sheets close sh deallocate sh end -- while of cursor files close cs deallocate cs dispose: drop table #providers drop table #xls drop table #tbls goto ret -- =================================================================== errors == err_nof: exec @ret=sp__err ''no xls files found'',@proc goto ret err_prv: exec @ret=sp__err ''"MSDASQL" and "Microsoft.ACE.OLEDB" providers are required'',@proc goto ret -- ===================================================================== help == help: exec sp__usage @proc,'' Scope Will search all XLS files under @path and create a xls_* view for each sheet Parameters @path is the path where search @root is the root name for tview as root_file_sheet otherwise will be used xls_path_file_sheet @opt options q|quiet do not show messages Notes * the new version uses only MSDASQL provider that require to install the MSAccess runtime. * if the file do not exists anymore, the select on view return a wrong message about gesitration of OLEDB that can be confused with previos point * can be necessary run this to exable linked server use msdb go sp_configure ''''show advanced options'''', 1 go reconfigure with override go sp_configure ''''ad hoc distributed queries'''', 1 go reconfigure with override go * resources: http://www.ashishblog.com/blog/importexport-excel-xlsx-or-xls-file-into-sql-server/ Examples sp__xls_attach "c:\shared_folders\backup_db\","xls_tests",@dbg=1 '' -- ===================================================================== exit == ret: return @ret end -- sp__xls_attach' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__xls_attach: -- ============================================================= sp__xls_convert select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__xls_convert',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100424 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__xls_convert') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__xls_convert') with nowait goto skip_sp__xls_convert end if @ver>100424 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__xls_convert') with nowait goto skip_sp__xls_convert end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__xls_convert') with nowait if exists( select top 1 null from sys.objects where name='sp__xls_convert' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__xls_convert] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,xls v:100424\s.zaglio: create aid code to import data from xls t:sp__xls_convert ''anagrafica'' */ CREATE proc sp__xls_convert @sheet sysname=null as begin set nocount on select @sheet=''%''+coalesce(@sheet+''%'','''') declare @crlf nchar(2) select @crlf=crlf from dbo.fn__sym() create table #src (lno int identity, line nvarchar(4000)) insert into #src select name from sysobjects where name like ''xls[_]''+@sheet update #src set line=''select ''+dbo.fn__str_exp(@crlf+ '' [%%] = convert(nvarchar(4000),nullif(ltrim(rtrim([%%])),''''''''))'', dbo.fn__flds_of(line,'','',null),'','')+@crlf +''into #''+line + @crlf +''from ''+quotename(line) + @crlf + @crlf exec sp__print_table ''#src'' drop table #src end' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__xls_convert: -- ============================================================== sp__xls_create select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__xls_create',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100508 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__xls_create') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__xls_create') with nowait goto skip_sp__xls_create end if @ver>100508 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__xls_create') with nowait goto skip_sp__xls_create end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__xls_create') with nowait if exists( select top 1 null from sys.objects where name='sp__xls_create' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__xls_create] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,xls v:100508\s.zaglio: cerate an xls files or add a sheet to an existins t:sp__xls_create ''test_form'',''c:\backup\test_form.xls'',@or=1 */ CREATE procedure [dbo].[sp__xls_create] @tbl sysname, @xls nvarchar(512), @or bit=0, @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=''sp__xls_create'',@ret=0 declare @sql nvarchar(4000) if @or=1 exec sp__drop @xls,@simul=0 select @sql=null select @sql=coalesce(@sql+'','','''')+quotename(c.name)+'' text'' from syscolumns c where id=object_id(@tbl) select @sql=''create table [''+@tbl+''](''+@sql+'')'' exec sp__xls_sql @xls,@sql,@dbg=@dbg goto ret help: exec sp__usage @proc,'' Parameters @or if 1 delete existing file '' ret: return @ret end -- sp__xls_create' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__xls_create: -- ================================================================= sp__xls_sql select @ver=null,@aut=null exec sp_executesql N' select @ver=cast(val1 as decimal(10,4)), @aut=val2 from dbo.fn__script_info(@obj,@typ,0) ',N'@obj sysname,@typ char(2),@ver numeric(10,4) out,@aut sysname out', @obj='sp__xls_sql',@typ='rv',@ver=@ver out,@aut=@aut out if not @ver is null begin if @ver=100508 begin if @aut!='s.zaglio' raiserror('local "%s.%s" with same version but different author', 16,1,@db,'sp__xls_sql') with nowait raiserror('skipped "%s.%s" because local is the same', 10,1,@db,'sp__xls_sql') with nowait goto skip_sp__xls_sql end if @ver>100508 begin raiserror('skipped "%s.%s" because local is more recent', 10,1,@db,'sp__xls_sql') with nowait goto skip_sp__xls_sql end end raiserror('re-creating "%s.%s"',10,1,@db,'sp__xls_sql') with nowait if exists( select top 1 null from sys.objects where name='sp__xls_sql' and schema_id=schema_id('dbo') ) drop proc [dbo].[sp__xls_sql] begin try exec dbo.sp_executesql @statement = N'/* leave this l:see LICENSE file g:utility,xls todo: rearrange code for a better error management v:100508\s.zaglio: execute a sql command into the xls sheet c:see http://www.simple-talk.com/sql/t-sql-programming/sql-server-excel-workbench/ t:sp__xls_sql ''c:\backup\test_form.xls'',''insert into test_form(id,i_val,f_val,d_val,v_val,t_val) select 1,2,3,4,5,6'' t:sp__xls_sql ''c:\backup\test_form.xls'',''delete from test_form'' -- delete not supported t:sp__xls_sql ''c:\backup\test_form.xls'',''update test_form set id=null where id=''''0'''''' t: create trigger tr_xls_test_form_test_form on xls_test_form_test_form instead of insert,update,delete as begin exec sp__xls_sql ''c:\backup\test_form.xls'',''insert into test_form(id,i_val,f_val,d_val,v_val,t_val) select 1,2,3,4,5,6'' end insert into xls_test_form_test_form select 1,2,3,4,5,6 drop trigger tr_xls_test_form_test_form */ CREATE procedure [dbo].[sp__xls_sql] @xls nvarchar(512), @sql nvarchar(4000), @dbg bit=0 as begin set nocount on declare @proc sysname,@ret int select @proc=''sp__xls_sql'',@ret=0 declare @objexcel int, @hr int, @command sysname, @strerrormessage sysname, @objerrorobject int, @objconnection int, @bucket int, @worksheet sysname, @connectionstring nvarchar(1024), @crlf nchar(2) select @crlf=crlf from dbo.fn__sym() select @connectionstring = ''provider=microsoft.jet.oledb.4.0;data source=%ds%;extended properties=excel 8.0'' select @connectionstring=replace (@connectionstring, ''%ds%'', @xls) select @strerrormessage=''making adodb connection '', @objerrorobject=null exec @hr=sp_oacreate ''adodb.connection'', @objconnection out if @hr=0 select @strerrormessage=''assigning connectionstring property "'' + @connectionstring + ''"'', @objerrorobject=@objconnection if @hr=0 exec @hr=sp_oasetproperty @objconnection, ''connectionstring'', @connectionstring if @hr=0 select @strerrormessage =''opening connection to xls, for file create or append'' if @hr=0 exec @hr=sp_oamethod @objconnection, ''open'' -- todo: convert @tbl in create with sp__script .... -- declare @tbl sysname,@sql nvarchar(4000),@crlf nchar(2) select @tbl=''test_form'',@crlf=char(13)+char(10) if @hr=0 select @strerrormessage =''executing ddl "''+@sql+''"'' if @dbg=1 exec sp__printf ''%s'',@sql -- first we have to delete existing if @hr=0 exec @hr=sp_oamethod @objconnection, ''execute'', @bucket out , @sql if @hr<>0 begin declare @source varchar(255), @description varchar(255), @helpfile varchar(255), @helpid int execute sp_oageterrorinfo @objerrorobject, @source output, @description output,@helpfile output,@helpid output select @strerrormessage=''error whilst '' +coalesce(@strerrormessage,''doing something'')+'', '' +coalesce(@description,'''') raiserror (@strerrormessage,16,1) end goto ret help: exec sp__usage @proc ret: if @objconnection!=0 exec @hr=sp_oadestroy @objconnection return @ret end -- sp__xls_create' end try begin catch exec #script_catch 'utility',@repeat if not error_number() in (208,207) begin select @emsg=error_message(),@esev=error_severity(),@ests=error_state() raiserror(@emsg,@esev,@ests) end end catch skip_sp__xls_sql: -- ########################## -- ## -- ## re-install/upgrade script tracer -- ## upgrade LOG_DDL if necessary -- ## -- ######################################################## exec sp__script_trace_db 'install' dispose: /* to manage dependencies we run eventually the script 2 or 3 times */ if exists( select top 1 null from #script_results where number in (208,207) -- invalid object, invalid column name and rep=@repeat -- a difference between x32 and x64 of mssql 2k5/8 and not message like '%''cpu_ticks_in_ms''%' ) begin select @repeat=@repeat+1 select @msg=replicate('#',80)+' REPEAT '+cast(@repeat as char) raiserror(@msg,10,1) if @repeat<3 goto begin_of_script else begin select db_name() db,* from #script_results raiserror('script repeats failure',16,1) end end exec sp__utility_setup @opt='run|end' -- select * from #script_results -- drop table #script_results end_of_script: -- finished:17-12-14T16:14