Wednesday, December 13, 2006

Perl: Free SQL Dependency Tracker

I am very impressed with RedGate SQl Depenency Tracker . This tool helped me lot in performing impact analysis of database object changed. Following Perl script is crude version of this tool. For given database object, it tracks dependent Stored Procedures, Functions, Views and Triggers drilled down to 3 levels. The only problem with this script it requires ODBC connection to Database.


#!/usr/bin/perl
use strict;
use DBI;

my $dbh = DBI->connect( "DBI:ODBC:localhost", 'sa', 'sa', { PrintError => 0 } );
die "Unable for connect to server $DBI::errstr"
unless $dbh;

my $search_object = $ARGV[0];

my $query = qq {
SELECT Name FROM dbo.sysobjects WHERE Xtype in ('P', 'FN', 'IF', 'V', 'TR', 'TF')
};

#print "Executing query: $query\n";
my $sth = $dbh->prepare($query)
or die "Couldn't prepare statement: " . $dbh->errstr;

$sth->execute or die "Couldn't execute statement: " . $sth->errstr;

my @object_array;
my %dbobjects;
while ( my @row = $sth->fetchrow_array ) {
if ( $row[0] !~ /^(dt_sys)/ ) {
push @object_array, $row[0];

}
}
$sth->finish;

foreach my $object (@object_array) {
my $text_query = qq {sp_helptext $object};
my $sth = $dbh->prepare($text_query)
or die "Couldn't prepare statement: " . $dbh->errstr;
$sth->execute or die "Couldn't execute statement: " . $sth->errstr;
my $text = '';
while ( my @row_text = $sth->fetchrow_array ) {

foreach (@row_text) {
$_ =~ s/--.*$//;
$text .= $_;
}

}
$text =~
s#/\*[^*]*\*+([^/*][^*]*\*+)*/("(\\.[^"\\])*"'(\\.[^'\\])*'.[^/"'\\]*)#defined $2 ? $2 : ""#gse;
$text =~ s/create.*?AS//msgi;
$dbobjects{$object} = $text;
$sth->finish;

#print $text, "\n--------------------------------------\n";
}

my @Level1 = FindDepenency($search_object);
foreach (@Level1) {
print $_, "\n";
my @Level2 = FindDepenency($_);
foreach (@Level2) {
print "------$_\n";
my @Level3 = FindDepenency($_);
foreach (@Level3) {
print "\t\t------$_\n";
}
}
}

sub FindDepenency {
my $key = shift;
my @return_arr;
foreach my $dbo ( keys %dbobjects ) {
next if ( lc($dbo) eq lc($key) );
if ( $dbobjects{$dbo} =~ /$key/msig ) {
push @return_arr, $dbo;
}
}
return @return_arr;
}

# Disconnect the database from the database handle.
$dbh->disconnect;

No comments: