# Tuesday, July 08, 2008

Search SQL Server Stored Procedures for any text string

Here's the SQL script I probably use most when I'm trying to work out dependencies and scope of development changes.  Query Analyzer allows you to search objects (hit F4 - it's cool!) and find objects by 'name', but there's no obvious way to search stored procs for a particular string.

SQL Server hides Stored Procedure code in the sysComments table (in each database), and so it's possible to search.  This is another script I found from not sure where (so can't really take credit).  It does a great job of scanning and even gives you line numbers.  It would be great to be able to just shove this into the master database, but you need to be in the context of the database you're searching in (or it would have to be amended somewhat to run some more 'dynamic' SQL). 

I have previously front-ended this for development databases with an ASP.NET page that simply runs the query substituting a parameter for the search text and connecting to the correct database.  The results show nicely in a grid.

Here's the code - just paste into a new query in your chosen database, change @SearchTerm and away you go...

 

SET NOCOUNT ON
GO

declare 
@dbname sysname
,@SearchTerm    varchar(100)
,@BlankSpaceAdded   
int
,@BasePos       int
,@CurrentPos    int
,@TextLength    int
,@LineId        int
,@AddOnLen      int
,@LFCR          int --lengths of line feed carriage return
,@DefinedLength int
,@obj_name    varchar(255)
,@prev_obj_name 
varchar(255)


/* NOTE: Length of @SyscomText is 4000 to replace the length of
** text column in syscomments.
** lengths on @Line, #CommentText Text column and
** value for @DefinedLength are all 255. These need to all have
** the same values. 255 was selected in order for the max length
** display using down level clients
*/
,@SyscomText    nvarchar(4000)
,@Line          
nvarchar(255)

set @SearchTerm 'MyTable'
set @dbname db_name()


set @SearchTerm '%' + @SearchTerm + '%'

Select @DefinedLength 255
SELECT @BlankSpaceAdded /*Keeps track of blank spaces at end of lines. Note Len function ignores
                             trailing blank spaces*/
CREATE TABLE #CommentText
(obj_name 
varchar(255)
 ,LineId    
int
 
,Text  nvarchar(255collate database_default)

/*
**  Make sure the @objname is local to the current database.
*/
if @dbname is not null and @dbname <> db_name()
        
begin
                raiserror
(15250,-1,-1)
        
end

    begin

        DECLARE 
ms_crs_syscom  CURSOR LOCAL
        FOR SELECT 
so.name, sc.text FROM syscomments sc
    
inner join sysobjects so
    
on so.id = sc.id
    where 
so.type 'P'
    
AND sc.encrypted 0
                
ORDER BY number, colid

        
FOR READ ONLY
    
end

/*
**  Get the text.
*/
SELECT @LFCR 2
SELECT @LineId 1


OPEN ms_crs_syscom

FETCH NEXT FROM ms_crs_syscom into @obj_name, @SyscomText

WHILE @@fetch_status >0
BEGIN

    SELECT  
@BasePos    1
    
SELECT  @CurrentPos 1
    
SELECT  @TextLength = LEN(@SyscomText)

    
IF @prev_obj_name <> @obj_name
        
--start again
        
SELECT @LineId 1
    
    
WHILE @CurrentPos  !0
    
BEGIN
        
--Looking for end of line followed by carriage return
        
SELECT @CurrentPos =   CHARINDEX(char(13)+char(10), @SyscomText, @BasePos)

        
--If carriage return found
        
IF @CurrentPos !0
        
BEGIN
            
/*If new value for @Lines length will be > then the
            **set length then insert current contents of @line
            **and proceed.
            */
            
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + @CurrentPos-@BasePos + @LFCR) > @DefinedLength
            
BEGIN
                SELECT 
@AddOnLen @DefinedLength-(isnull(LEN(@Line),0) + @BlankSpaceAdded)
                
INSERT #CommentText VALUES
                
( @obj_name,
          @LineId,
                  
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
                
SELECT @Line = NULL, @LineId @LineId + 1,
                       @BasePos 
@BasePos + @AddOnLen, @BlankSpaceAdded 0
            
END
            SELECT 
@Line    = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
            
SELECT @BasePos @CurrentPos+2
            
INSERT #CommentText VALUES( @obj_name, @LineId, @Line )
            
SELECT @LineId @LineId + 1
            
SELECT @Line = NULL
        END
        ELSE
        
--else carriage return not found
        
BEGIN
            IF 
@BasePos <@TextLength
            
BEGIN
                
/*If new value for @Lines length will be > then the
                **defined length
                */
                
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + @TextLength-@BasePos+1 ) > @DefinedLength
                
BEGIN
                    SELECT 
@AddOnLen @DefinedLength - (isnull(LEN(@Line),0) + @BlankSpaceAdded)
                    
INSERT #CommentText VALUES
                    
( @obj_name,
              @LineId,
                      
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
                    
SELECT @Line = NULL, @LineId @LineId + 1,
                        @BasePos 
@BasePos + @AddOnLen, @BlankSpaceAdded 0
                
END
                SELECT 
@Line = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'')
                
if LEN(@Line) < @DefinedLength and charindex(' ', @SyscomText, @TextLength+1 ) > 0
                
BEGIN
                    SELECT 
@Line @Line + ' ', @BlankSpaceAdded 1
                
END
            END
        END
    END
    
--Save previous name
    
SET @prev_obj_name @obj_name
    
FETCH NEXT FROM ms_crs_syscom into @obj_name, @SyscomText
END

IF 
@Line is NOT NULL
    INSERT #
CommentText VALUES( @obj_name, @LineId, @Line )

select from #CommentText 
where  patindex(@SearchTerm, text) <> 0

CLOSE  ms_crs_syscom
DEALLOCATE     ms_crs_syscom

DROP TABLE     #CommentText


Colorized by: CarlosAg.CodeColorizer
posted on Tuesday, July 08, 2008 9:38:31 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]

Generate SQL Inserts from existing data

This is one from the archives that obviously got away.  I had need for this today so thought I'd post so I don't have to look so hard next time!

It's pretty much a case of create the SP in your chosen database and run with a tablename as the parameter.  I originally found this on one of the SQL sites (probably SQLServerCentral), and amended it slightly to add some basic filtering in the @where parameter.

There's a few limitations from memory - with blob, image and text fields, but for your average tables this will probably do the trick just fine.

I've also used a different method that basically builds up a single INSERT with SELECT 'literal values' UNION SELECT 'literal values'.  That works fine and is potentially easier to control transaction-wise as everthing's in a single statement.  Anyway here's the code....

if exists (select from dbo.sysobjects where id = object_id(N'[dbo].[usp_InsertGenerator]'and OBJECTPROPERTY(idN'IsProcedure'1)
drop procedure [dbo].[usp_InsertGenerator]
GO


CREATE PROC 
dbo.usp_InsertGenerator
(@tableName 
varchar(100), @where varchar(1000= NULLas
 
--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR 
SELECT 
column_name,data_type FROM information_schema.columns WHERE table_name @tableName
OPEN cursCol
DECLARE @string nvarchar(3000--for storing the first half of INSERT statement
DECLARE @stringData nvarchar(3000--for storing the data (VALUES) related statement
DECLARE @dataType nvarchar(1000--data types returned for respective columns
SET @string='INSERT '+@tableName+'('
SET @stringData=''
 
DECLARE @colName nvarchar(50)
 
FETCH NEXT FROM cursCol INTO @colName,@dataType
 
IF @@fetch_status<>0
 
begin
 print 
'Table '+@tableName+' not found, processing skipped.'
 
close curscol
 
deallocate curscol
 
return
END
 
WHILE 
@@FETCH_STATUS=0
BEGIN
IF 
@dataType in ('varchar','char','nchar','nvarchar')
BEGIN
 SET 
@stringData=@stringData+''''+'''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'
END
ELSE
if 
@dataType in ('text','ntext'--if the datatype is text or something else 
BEGIN
 SET 
@stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(2000)),'''')+'''''',''+'
END
ELSE
IF 
@dataType 'money' --because money doesn't get converted from varchar implicitly
BEGIN
 SET 
@stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'
END
ELSE 
IF 
@dataType='datetime'
BEGIN
 SET 
@stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'
END
ELSE 
IF 
@dataType='image' 
BEGIN
 SET 
@stringData=@stringData+'''''''''+isnull(cast(convert(varbinary,'+@colName+') as varchar(6)),''0'')+'''''',''+'
END
ELSE 
--presuming the data type is int,bit,numeric,decimal 
BEGIN
 SET 
@stringData=@stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'
END
 
SET 
@string=@string+@colName+','
 
FETCH NEXT FROM cursCol INTO @colName,@dataType
END
DECLARE 
@Query nvarchar(4000)
 
SET @query ='SELECT '''+substring(@string,0,len(@string)) + ') VALUES(''+ ' substring(@stringData,0,len(@stringData)-2)+'''+'')'' FROM '+@tableName
IF @where IS NOT NULL
 SET 
@query @query + ' where ' + @where
 
exec sp_executesql @query
 
CLOSE cursCol
DEALLOCATE cursCol
GO

Colorized by: CarlosAg.CodeColorizer
posted on Tuesday, July 08, 2008 9:18:47 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, July 07, 2008

Upgrading TortoiseSVN, Subversion 1.5 and AnkhSVN.

I thought I'd upgrade to v1.5 of TortoiseSVN this morning (leaving the server on V1.4.x) - of course completely forgetting that I use AnkhSVN in Visual Studio. 

New versions of TortoiseSVN and Subversion tend to upgrade the format for Working Copies.  This means AnkhSVN (1.02) was no longer compatible with my 'new' Working Copy and I got the following error...

This client is too old to work with Working copy 'xxx'. Please get a newer Subversion client.

Thankfully AnkhSVN 2.0 is on the way and I downloaded a nightly build (2.0.4523.91) and installed (without uninstalling 1.0.2).  I usually do this to 'test' whether people write good installers.  Most people do the right thing with AutoUpgrade and 1.0.2 dutifully disappeared.

I loaded up Visual Studio with the same solution and - 'Where's my AnkhSVN menus gone?'.  As V2.0 is not even Alpha yet there's not much in the way of obvious help on the Collabnet site.  The community area may have more, but I luckily didn't need it.

I noticed in the application folder that there's now an Ankh.Scc.dll.  Well blow me if they haven't gone and made it a 'standard' Visual Studio SCC Provider!  Tools --> Options --> Source Control --> Plug-in Selection.  There it is.

Once you've got over that, then you might find a few little errors here and there, but the main difference is that instead of an ANKH menu on Tools and in the Solution Explorer context menu - you get a Subversion context menu. 

I'm liking it so far.  I think it's probably stable enough to put your faith in and make the jump to SVN 1.5.

Update (08/07/2008) 
I submitted a bug report yesterday on an error I encountered (from the nice 'send error details' link) and got a reply saying 'fixed in latest build' the next day.  This bodes well!!!  Reasons to pay money for VisualSVN now disappearing fast...

Update (23/07/2008)

AnkhSVN v2.0 now officially out (that was a quick alpha/beta phase!)

posted on Monday, July 07, 2008 10:37:45 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [1]
# Friday, July 04, 2008

Invalid Postback or Callback Argument - ASP.NET. One cause

Just been getting this error.  It's quite common, especially if you're using Ajax.  I got the error for an altogether more 'schoolboy error' reason.

I had a textbox control e.g. called 'customerName', and two radio buttons controlling whether to show the customer name.  These had a 'GroupName' of customerName, and this caused the error.  You need the GroupName to associate the radio buttons together, but the postback mechanism obviously sees that as the control identifier.  Silly boy. 

The naming was pretty bad in any case and actually prompted me to take more of a long hard look at the UI to tidy it up so no such conflict would arise.

posted on Friday, July 04, 2008 4:21:22 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Wednesday, July 02, 2008

ASP.NET - The name xxx does not exist in the current context

I recently converted a Web Site to a Web Application project, and as it had been a while I tripped up on a few things. 

First of all I made the mistake of creating a new Web Application and pasting all the web files in there (I was intending to split some of the site into another Class Library), and I wanted to port to another file structure.  I mistakenly thought it would be easier to do this 'before' changing to the WAP.

I then of course got a gazillion compiler errors (well - 1436 to be exact) on the new project.  The vast majority of which were 'The name xxx does not exist in the current context'.  Yes it does! (I protested).  Well.  That showed mistake number 2.

If you want to convert then use the 'Convert to Web Application' option on the Web Site properties (or on the individual pages if necessary).  This does a number of things:
  1. Sorts out your project structure
  2. Changes 'CodeFile' to 'CodeBehind' and other directives
  3. Adds a designer file for pages and controls
  4. Other stuff that you shouldn't bother yourself with etc...
The compiler errors were due to the fact that the WAP model expects pages to be structured in a certain way, and although the 'code' looks fine (and Resharper was green all the way) it won't compile 'cos the designer files are missing and hence so are the definitions the compiler's looking for.

See Steven Smith's post on some other tips for converting projects.

posted on Wednesday, July 02, 2008 11:07:48 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, June 30, 2008

Del.icio.us - FavPal.NET is dead?

This sounds pretty unlikely, but I'm a new (and very enthusiastic) del.icio.us user (and have to think hard about where to put the dots every time I type it).  I guess you can't jump on 'every' bandwagon.  I tend to discover stuff that I 'need' these days rather than get too 'wowed' by yet another networking site.

I developed a tool called FavPal.NET (don't worry - I'm sure you haven't heard of it!), a few years back as I saw there was nothing that allowed you to search through browser bookmarks with any degree of speed or accuracy.  It was a tray app that kept a 'cache' pool of IE instances (as load time was pretty bad back then), and allowed you to search through your favourites, then load up URL's into a cached instance in double-quick time.  This served two purposes

  1. Search Favourites
  2. Load IE quickly

Del.icio.us obviously more than scores with requirement 1 as it allows you to keep your bookmarks centrally (BTW - I also use the IGoogle bookmarks gadget for 'home page' access to my most frequently used stuff).  One thing was still lacking - an 'integrated' search within the browser (or rather a search without having to point your browser to del.icio.us), but now there's an IE extension (for IE6/7) that sits as a sidebar (nice).

I noticed there's a Delicious.NET framework, and I'm still not terribly satisfied with the initial application load speed of any browser (even Firefox and Safari), so maybe FavPal's not quite dead.  The search functionality could now simply hook into del.icio.us and still use the cache.  With tabbed browsing on IE7 now though the object model may well have changed.  If anyone wants to have a crack at it you're more than welcome, and I'll send you the code, as it got removed from the late lamented gotdotnet workspaces.

Of course the load speed will ineviatably go up with the more plugins like del.icio.us you bloat the browser with - d'oh!

posted on Monday, June 30, 2008 8:24:27 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Thursday, June 19, 2008

Developer Highway Code - Building secure software with .NET

Had some security training yesterday (don't normally get training as a contractor so I was very happy to go along). 

The trainer mentioned the Developer Highway Code from Microsoft (seemingly originating from the UK based on the style of the publication).  Not only does it look cool, and have some rather amusing geek stuff (just see the 'Reduce Coffee Now' sign on the cover), it also has some really practical advice for people wanting to build secure applications.

Download it from Microsoft

posted on Thursday, June 19, 2008 10:23:35 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, June 16, 2008

If, For, Switch, but...

I love that Scott Hanselman challenges his own as well as others' thoughts on how to solve technical problems.

I'm not making any judgements about junior devs vs. senior devs. I'm talking about idioms and "vocab." I think that using only if, for and switch is the Computer Programmer equivalent of using "like" in every sentence. Like, you know, like, he was all, like, whatever, and I was like, dude, and he was, like, ewh, and I was like meh, you know?

There's some good examples on forcing yourself to learn new objects, features and constructs through refactoring.  If you don't refactor then you'll never know...

posted on Monday, June 16, 2008 9:32:26 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Friday, June 13, 2008

Installing Multiple versions of Internet Explorer with Multiple_IE

I don't have the time, inclination or grunty machines to play around with Virtual machines just so I can test a website in IE6 (after IE7 'magically' appeared).  When I say 'test', I actually mean hack an IE-specific CSS together with some box-model workarounds.  I digress...

Enter Multiple_IE.  It's not perfect (it's a hack in itself), but it suffices in most cases so kudos for that...  You even get the nostalgia of IE3

posted on Friday, June 13, 2008 2:17:00 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Wednesday, June 11, 2008

Code Monkey Song

I'd totally forgotten about this - don't want to lose it...

http://www.jonathancoulton.com/2006/04/14/thing-a-week-29-code-monkey/

posted on Wednesday, June 11, 2008 10:17:46 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]