RE: stored procedure names
- From: Linchi Shea <LinchiShea@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Fri, 31 Jul 2009 11:24:02 -0700
I have a Perl script that can address both your questions. I can't attach it
using this Web interface, but will do with a news reader that allows
attaching a file. But let me paste the code here (the format probably sucks).
Linchi
## Begin script
use strict;
use Data::Dumper;
my $server = 'YourServerName';
my $procDependRef;
my $msProcRef = getMSProcNames($server);
my $procRef = getProcNames($server);
#print Dumper($procRef);
for my $db (keys %$procRef)
{
for my $proc ( @{$procRef->{$db}} )
{
my $sql = qq/set nocount on; EXEC sp_helptext \'$proc\';/;
my $cmd = qq/osql.exe -S$server -E -d$db -n -h-1 -w5000 -Q\"$sql\"/;
my $script = `$cmd`;
$script =~ s/\/\*([^\/]|\/[^\*])*\*\///;
$script =~ s/\-\-.*$//mg;
# my $scriptRef = parseTSQL($script);
my ($proc_inside, $dependRef) = findExecProc($script);
if ($proc !~ /$proc_inside/i)
{
warn "***Error: The proc name does not match the name in
syscomments.";
}
#$procDependRef->{$db}->{$proc} = $dependRef;
# print "Database=$db, Proc=$proc\n";
for my $dep (@{$dependRef})
{
# print "\t\t$dep\n";
if ($dep =~ /^\s*[a-zA-Z]+\s*$/)
{
next unless (dbaInSet($dep, $procRef->{$db}));
}
if ($dep =~ /^\s*sp\_\w+\s*$/)
{
if (dbaInSet($dep, $msProcRef))
{
$dep = $server . '.master.dbo.' . $dep;
}
}
if ($dep !~ /\./)
{
$dep = $server . '.' . $db . '.dbo.' . $dep;
}
elsif ($dep =~ /^\s*(\w+)\.(\w+)\s*$/)
{
$dep = $server . '.' . $db . '.' . $dep;
}
elsif ($dep =~ /^\s*(\w+)\.\.(\w+)\s*$/)
{
$dep = $server . '.' . $1 . '.dbo.' . $2;
}
elsif ($dep =~ /^\s*(\w+\.\w+\.\w+)\s*$/)
{
$dep = $server . '.' . $dep;
}
elsif ($dep =~ /^\s*(\w+)\.(\w+)\.\.(\w+)\s*$/)
{
$dep = $1 . '.' . $2 . '.' . '.dbo.' . $3;
}
elsif ($dep =~ /^\s*(\w+\.\w+\.\w+\.\w+)\s*$/)
{
$dep = $dep;
}
else
{
warn "**Error: $dep is not in the expected format."
}
print "$server,$db,$server.$db.$proc,$dep\n";
}
undef $script;
}
}
#print Dumper($procDependRef);
#########################
sub getMSProcNames {
#########################
my $server = shift;
my @procs;
my $sql = q/set nocount on; select name from master..sysobjects where
type in ('P', 'X') and name like 'sp_%'/;
my $cmd = qq/osql.exe -S$server -E -n -h-1 -w1000 -Q\"$sql\"/;
my $procs = `$cmd`;
for my $proc (split /\n/, $procs)
{
$proc =~ s/^\s*//;
$proc =~ s/\s*$//;
$proc = join('.', split /\s+/, $proc);
push @procs, $proc;
}
return [@procs];
} # getMSProcNames()
#########################
sub getProcNames {
#########################
my $server = shift;
my $procRef;
my $sql = q/set nocount on; select @@version/;
my $cmd = qq/osql.exe -S$server -E -n -h-1 -w1000 -Q\"$sql\"/;
my $version = `$cmd`;
if ($version =~ /\W8\.\d+\.\d+/)
{
$version = 'SQL2000';
}
$sql = q/set nocount on; select name from master..sysdatabases where
name not in ('master', 'tempdb', 'model', 'msdb', 'pubs', 'AdventureWorks')/;
$cmd = qq/osql.exe -S$server -E -n -h-1 -w1000 -Q\"$sql\"/;
my $dbs = `$cmd`;
for my $db (split /\s+/, $dbs)
{
next if $db =~ /^\s*$/;
if ($version eq 'SQL2000')
{
$sql = q/set nocount on; select user_name(uid), name from
sysobjects where type ='P' and objectproperty(id, N'IsMSShipped') != 1/;
}
else
{
$sql = q/set nocount on; select schema_name(uid), name from
sysobjects where type ='P' and objectproperty(id, N'IsMSShipped') != 1/;
}
$cmd = qq/osql.exe -S$server -E -d$db -n -h-1 -w1000 -Q\"$sql\"/;
my $procs = `$cmd`;
for my $proc (split /\n/, $procs)
{
$proc =~ s/^\s*//;
$proc =~ s/\s*$//;
$proc = join('.', split /\s+/, $proc);
push @{$procRef->{$db}}, $proc;
}
}
return $procRef;
} # getProcNames()
##################################
sub parseTSQL {
##################################
my($script) = shift;
use Parse::RecDescent;
# $::RD_TRACE = 0;
$::RD_HINT = 0;
my $Grammar=<<'EOGRAMMAR';
{ my $cnt;
my $sqlRef = {
code => ''
};
}
program : <skip:''> part(s) /\Z/ { $sqlRef }
part : comment
| TSQL_code
| string
| double_identifier
| bracket_identifier
comment : ansi_comment
{ $sqlRef->{code} .= ' ';
}
| delimited_comment
{ $sqlRef->{code} .= ' ';
}
ansi_comment : m{ (--[^\n]*)\n }x
{ $item[1] }
delimited_comment : simple_comment
{ $item[1] }
| nested_comment
{ $item[1] }
simple_comment : comment_opener comment_closer
{ $item[1] . $item[2] }
| comment_opener pure_comment(s) comment_closer
{ $item[1] . join('', @{$item[2]}) .
$item[3] }
nested_comment : comment_opener raw_comment(s) comment_closer
{ $item[1] . join('', @{$item[2]}) .
$item[3] }
raw_comment : pure_comment(?) delimited_comment pure_comment(?)
{ join('', @{$item[1]}) . $item[2] .
join('', @{$item[3]}) }
comment_opener : m{ /\* }x
{ $item[1] }
comment_closer : m{ \*/ }x
{ $item[1] }
pure_comment : m{ (?: [^*/]+ # no * or /
| \*(?!/) # if *, then not
followed by /
| \/(?!\*) # if /, then not
followed by *
)+
}x
{ $item[1] }
TSQL_code : m{([^\"/\'\-\[]+ # one or more non-delimiters
( # then (optionally)...
/[^*] # a potential, but not actual,
comment delimiter
| # or
-[^\-]
)? #
)+ # all repeated once or more
}x
{ $sqlRef->{code} .= $item[1] }
string : m{\'(([^\'] | (\'\'))*)\'}x
{
$sqlRef->{code} .= $item[1];
}
double_identifier : m{\"
(([^\"] | (\"\"))+)
\"
}x
{
$sqlRef->{code} .= $item[1];
}
bracket_identifier : m{\[
([^\[\]]+)
\]
}x
{
$sqlRef->{code} .= $item[1];
}
EOGRAMMAR
my $parser = new Parse::RecDescent $Grammar or die "***Error: invalid
TSQL grammar.";
$parser->program($script) or die "***Error: malformed TSQL script.";
} # parseTSQL
##################################
sub findExecProc {
##################################
my ($batch) = @_;
my $db;
my $proc;
my @depends;
if ($batch =~
/\bcreate\s+(?:proc|procedure)\s+((\[)?\w+(\])?\.(\[)?\w+(\])?|(\[)?\w+(\])?)/i) {
$proc = $1;
while ($batch =~ /\b(?:exec|execute)\s+
(?:\@\w+\s*=\s*)?
(
(\[)?\w+(\])?\.(\[)?\w+(\])?\.(\[)?\w*(\])?\.(\[)?\w+(\])?
| (\[)?\w+(\])?\.(\[)?\w*(\])?\.(\[)?\w+(\])?
| (\[)?\w+(\])?\.(\[)?\w+(\])?
| (\[)?\w+(\])?
)
/igx
)
{
push @depends, $1;
}
}
my $ref;
for my $depend (@depends)
{
$depend =~ s/\[//g;
$depend =~ s/\]//g;
$ref->{$depend} = 1;
}
($proc, [keys %$ref]);
} # findExecProc
#####################
sub dbaInSet {
#####################
my($element, $setRef) = @_;
$element = quotemeta($element);
grep(/^$element$/, @$setRef);
} # dbaInSet
## end script
"JB" wrote:
This is a two part question having to do the SP names. ( SQLServer 2000).
1) SPs have two names, the name that apprears in the list of SPs(In e.g.
Enterprise Manager) and the name in the CREATE PROCEDURE text. SQL Server is
quite happy allow these names to be different until either the text is edited
or the SP is executed. So question 1 is, "Is there a system SP that can be
used to find all the SPs in a database for which the names don't match?"
This issues comes up when I rename several SPs and then forget to fix up all
the name in the CREATE PROCUDURE text.
2) The second question is whether or not there is a procedure that can be
used to search all the SPs in the database for EXECUTE statements that are
pointing to invalid SP names. SQL Server implements deferred name resolution
during editing which is good but it would also be useful to be able to turn
this off now and then to find errors before execution. User functions insist
on names being valid during editing which means a little more bother with
editing but saves time during testing.
--
JB
- References:
- stored procedure names
- From: JB
- stored procedure names
- Prev by Date: Re: stored procedure names
- Next by Date: Re: How to create multiple temporary tables from a single view
- Previous by thread: Re: stored procedure names
- Next by thread: Upgrade to SQL 2008 Pain with C#
- Index(es):
Relevant Pages
|