Technical Article

Search for text in procedures and show context

,

This script will search for text within stored procedures and udf's. As a bonus, it will also diplay a user-configurable number of lines from each stored proc to show the search text "in context" so you can tell if it is something you need to deal with without having to open every proc manually.

set nocount on
declare @SearchStr  varchar(100), @Lines  int, @ShowFullProc bit

-- **************************************************************
set @SearchStr = '%SearchText%'
set @Lines = 20
set @ShowFullProc = 0
-- **************************************************************

declare@ProcId  int
 , @ProcChunk  nvarchar(4000)
 , @ProcLine  nvarchar(1000)
 , @PartialLine  nvarchar(1000)
 , @ProcName  sysname
 , @LineNbr  int
 , @ProcChunkLen int
 , @SubStringStart int
 , @SubStringEnd int
 , @CRIdx  int
 , @LFIdx  int
 , @DelimLen  smallint
 , @ProcLineMatch int

declare @ProcIds table
 (
Id  int
 , ProcName sysname
, ProcType varchar(15)
)

declare @ProcLines table
 (
 LineNbr  int
 , ProcLine nvarchar(3800)
 )

INSERT INTO @ProcIds
 SELECT DISTINCT id
, name
, (Case when OBJECTPROPERTY(id, N'IsProcedure') = 1 then 'Procedure'  when OBJECTPROPERTY(id, N'IsScalarFunction') IS NOT NULL then 'Function' else 'Unknown Type' end ) as Type
FROM sysobjects
 WHERE ( OBJECTPROPERTY(id, N'IsProcedure') = 1 OR OBJECTPROPERTY(id, N'IsScalarFunction') IS NOT NULL )
  AND
  id IN ( SELECT DISTINCT id
    FROM syscomments
    WHERE text LIKE @SearchStr
   )

SELECT ProcType, ProcName 
FROM @ProcIds
ORDER BY ProcName

set @PartialLine = ''

declare ProcIds cursor local for
SELECT id, ProcName
FROM @ProcIds
ORDER BY ProcName

open ProcIds
fetch next from ProcIds into @ProcId, @ProcName

while @@FETCH_STATUS = 0
     begin
set @LineNbr = 1
set @ProcLine = ''
 
declare ProcDef cursor local for
SELECT RTRIM(text)
FROM syscomments
WHERE id = (SELECT id
FROM sysobjects
WHERE name = @ProcName)
ORDER BY colid
 
open ProcDef
fetch next from ProcDef into @ProcChunk
 
while @@FETCH_STATUS = 0
     begin
-- Get individual lines into ProcLines table
set @ProcChunkLen = len(@ProcChunk)
set @SubStringStart = 1
set @SubStringEnd = 0
  
while @SubStringStart <= @ProcChunkLen
     begin
-- The typical line break is a CR (13)  and LF (10) but it can also be one or the other 
-- but the sequence should always be CR LF
set @CRIdx = charindex(char(13), @ProcChunk, @SubStringStart)
set @LFIdx = charindex(char(10), @ProcChunk, @SubStringStart)
   
if @CRIdx = 0 and @LFIdx = 0
     begin
set @SubStringEnd = @ProcChunkLen + 1
set @DelimLen = 0
     end
else
     begin
if @CRIdx < @LFIdx
     begin
if @CRIdx = 0
     begin
set @SubStringEnd = @LFIdx
set @DelimLen = 1
     end
else
     begin
set @SubStringEnd = @CRIdx 
      
 if @LFIdx - @CRIdx = 1
 set @DelimLen = 2
 else
set @DelimLen = 1
     end
     end
else
     begin
if @LFIdx = 0
     begin
set @SubStringEnd = @ProcChunkLen + 1
set @DelimLen = 0
     end
else
     begin
set @SubStringEnd = @LFIdx
set @DelimLen = 1
     end
     end
     end

if @SubStringStart > @ProcChunkLen set @SubStringStart = @ProcChunkLen

set @ProcLine = rtrim(substring(@ProcChunk, @SubStringStart, @SubStringEnd - @SubStringStart))
set @SubStringStart = @SubStringEnd + @DelimLen
set @ProcLine = @PartialLine + @ProcLine
set @PartialLine = ''

if @DelimLen = 0 and len(@ProcLine) > 0
     begin
set @PartialLine = @ProcLine
     end
else
     begin
INSERT INTO @ProcLines
(
LineNbr
, ProcLine
)
VALUES
(
@LineNbr
, @ProcLine
)
    
set @LineNbr = @LineNbr + 1
set @ProcLine = ''
     end
     end
  
fetch next from ProcDef into @ProcChunk
     end
 
close ProcDef
deallocate ProcDef

/* Display matching lines and context for currenct proc */declare ProcLineMatches cursor local for
SELECT LineNbr
FROM @ProcLines
WHERE ProcLine LIKE @SearchStr
ORDER BY LineNbr
 
open ProcLineMatches

fetch next from ProcLineMatches into @ProcLineMatch

set rowcount @Lines

while @@FETCH_STATUS = 0
     begin
print @ProcName + ' (at line ' + cast(@ProcLineMatch as varchar) + ')' + char(13) + char(10) + '================================================'

SELECT LineNbr
, ProcLine
FROM @ProcLines
WHERE LineNbr > @ProcLineMatch - (@Lines / 2)
ORDER BY LineNbr

print ''

fetch next from ProcLineMatches into @ProcLineMatch
     end

close ProcLineMatches
deallocate ProcLineMatches

set rowcount 0

/* If desired, show the entire stored procedure. */if @ShowFullProc = 1
     begin
SELECT LineNbr
, ProcLine
FROM @ProcLines
ORDER BY LineNbr
     end

delete @ProcLines

fetch next from ProcIds into @ProcId, @ProcName
     end

close ProcIds
deallocate ProcIds

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating