#!/usr/local/bin/perl -w
#
# $Id: dbschema.pl,v 1.1 1997/11/03 18:08:41 mpeppler Exp $
#
# dbschema.pl A script to extract a database structure from
# a Sybase database
#
# Written by: Michael Peppler (mpeppler@mbay.net)
# Substantially rewritten by David Whitmarsh from a partial
# System 10 implementation by Ashu Joglekar
# Ported to DBI/DBD::Sybase by Michael Peppler
#
# Last Mods: 31 October 1997
#
# Usage: dbschema.pl -d database -o script.name -t pattern -s server -v
# where database is self-explanatory (default: master)
# script.name is the output file (default: script.isql)
# pattern is the pattern of object names (in sysobjects)
# that we will look at (default: %), and server is
# the server to connect to (default, the value of $ENV{DSQUERY}).
#
# -v turns on a verbose switch.
#
# Changes: 11/18/93 - bpapp - Put in interactive SA password prompt
# 11/18/93 - bpapp - Get protection information for views and
# stored procedures.
# 02/22/94 - mpeppler - Merge bpapp's changes with itf version'
# 09/15/94 - mpeppler - Minor changes for use with Sybperl2
# alpha1
# 13/10/95 - Ashu Joglekar - System 10 w/o RI
# 11/11/96 - David Whitmarsh -
# Use Sybase::DBlib
# System 10 declarative RI
# constraints
# Eliminate key truncation problems
# Optional password command line
# Debugged and strictified
# Some index/key options
# 17/2/97 - Michael Peppler
# Fixed small ',' problem in printKeys()
# 11/3/97 - David Whitmarsh
# bug handling user defined types used as
# identity columns.
# addtype now has scale, prec
# removed spurious addtypes for nchar etc.
# null/not null/identity on types
# 12/3/97 - Michael Peppler
# Added -i switch to set an alternate interfaces
# file.
#
# If anyone knows a way to distinguish between key and reference
# declarations made at column and table level, let me know.
#------------------------------------------------------------------------------
use strict;
use DBI;
use Getopt::Std;
sub getPerms;
sub getObj;
sub printKeys;
sub getComment;
sub PrintCols;
sub DumpTable;
my ($dbh, @dat, $dat, $udflt, $urule, %udflt, %urule, %tables, @tabnames, @col);
my $sth;
my ($rule, $dflt, $date, $name);
select (STDOUT); $| = 1; # make unbuffered
getopts ('u:p:d:t:o:s:i:v');
$Getopt::Std::opt_u = `whoami` unless $Getopt::Std::opt_u;
$Getopt::Std::opt_d = 'master' unless $Getopt::Std::opt_d;
$Getopt::Std::opt_o = 'script.isql' unless $Getopt::Std::opt_o;
$Getopt::Std::opt_t = '%' unless $Getopt::Std::opt_t;
$Getopt::Std::opt_s = $ENV{DSQUERY} unless $Getopt::Std::opt_s;
open(SCRIPT, "> $Getopt::Std::opt_o") || die "Can't open $Getopt::Std::opt_o: $!\n";
open(LOG, "> $Getopt::Std::opt_o.log") || die "Can't open $Getopt::Std::opt_o.log: $!\n";
#
# Log us in to Sybase as '$Getopt::Std::opt_u' and prompt for password.
#
if (!$Getopt::Std::opt_p) {
print "\nPassword: ";
system("stty -echo");
chop($Getopt::Std::opt_p = <>);
system("stty echo");
}
my $ifile = '';
if($Getopt::Std::opt_i) {
$ifile = "interfaces=$Getopt::Std::opt_i";
}
$dbh = DBI->connect("dbi:Sybase:server=$Getopt::Std::opt_s;$ifile", $Getopt::Std::opt_u, $Getopt::Std::opt_p);
$dbh->do("use $Getopt::Std::opt_d");
$date = scalar(localtime);
print "dbschema.pl on Database $Getopt::Std::opt_d\n";
print LOG "Error log from dbschema.pl on Database $Getopt::Std::opt_d on $date\n\n";
print LOG "The following objects cannot be reliably created from the script in $Getopt::Std::opt_o.
Please correct the script to remove any inconsistencies.\n\n";
print SCRIPT
"/* This Isql script was generated by dbschema.pl on $date. */\n";
print SCRIPT "\nuse $Getopt::Std::opt_d\ngo\n"; # Change to the appropriate database
# first, Add the appropriate user data types:
#
print "Add user-defined data types...";
print SCRIPT
"/* Add user-defined data types: */\n\n";
$sth = $dbh->prepare (<<SQLEND
select s.length, s.name, st.name,
object_name(s.tdefault),
object_name(s.domain),
s.prec, s.scale,
s.allownulls,
isnull (s.ident, 1)
from dbo.systypes s, dbo.systypes st
where st.type = s.type
and s.usertype > 100 and st.usertype < 100
and st.name not in ('intn', 'nvarchar', 'sysname', 'nchar')
SQLEND
);
$sth->execute;
while((@dat = $sth->fetchrow))
{
print SCRIPT "sp_addtype $dat[1], ";
($dat[2] =~ /char\b|binary\b/ and
print SCRIPT "'$dat[2]($dat[0])'")
or ($dat[2] =~ /\bnumeric\b|\bdecimal\b/ and
print SCRIPT "'$dat[2]($dat[5],$dat[6])'")
or print SCRIPT "$dat[2]";
(($dat[8] == 1) and print SCRIPT ", 'identity'")
or (($dat[7] == 1) and print SCRIPT ", 'null'")
or print SCRIPT ", 'not null'";
print SCRIPT "\ngo\n";
# Now remember the default & rule for later.
$urule{$dat[1]} = $dat[4] if defined($dat[4]);
$udflt{$dat[1]} = $dat[3] if defined($dat[3]);
}
$sth->finish();
print "Done\n";
print "Create rules...";
print SCRIPT
"\n/* Now we add the rules... */\n\n";
getObj('Rule', 'R');
print "Done\n";
print "Create defaults...";
print SCRIPT
"\n/* Now we add the defaults... */\n\n";
getObj('Default', 'D');
print "Done\n";
print "Bind rules & defaults to user data types...";
print SCRIPT "/* Bind rules & defaults to user data types... */\n\n";
while(($dat, $dflt)=each(%udflt))
{
print SCRIPT "sp_bindefault $dflt, $dat\ngo\n";
}
while(($dat, $rule) = each(%urule))
{
print SCRIPT "sp_bindrule $rule, $dat\ngo\n";
}
print "Done\n";
print "Create Tables & Indices...";
print "\n" if $Getopt::Std::opt_v;
# the fourth column set to 'N' becomes the indicator that this table has been
# printed
$sth = $dbh->prepare (<<SQLEND
select o.name, u.name, o.id, 'N'
from dbo.sysobjects o, dbo.sysusers u
where o.type = 'U' and o.name like '$Getopt::Std::opt_t' and u.uid = o.uid
order by o.name
SQLEND
);
$sth->execute;
while((@dat = $sth->fetchrow))
{
$tables{$dat[1] . "." . $dat[0]} = [ @dat ];
@tabnames = ( @tabnames, $dat[1] . "." . $dat[0] );
}
$sth->finish;
foreach $name (@tabnames) {
DumpTable ($tables{$name}, ());
}
print "Done\n";
#
# The key definitions - sp_primarykey etc, not constraints
# Primary keys first, then foreign and common
#
printKeys ();
#
# Now create any views that might exist
#
print "Create views...";
print SCRIPT
"\n/* Now we add the views... */\n\n";
getObj('View', 'V');
print "Done\n";
#
# Now create any stored procs that might exist
#
print "Create stored procs...";
print SCRIPT
"\n/* Now we add the stored procedures... */\n\n";
getObj('Stored Proc', 'P');
print "Done\n";
#
# Now create the triggers
#
print "Create triggers...";
print SCRIPT
"\n/* Now we add the triggers... */\n\n";
getObj('Trigger', 'TR');
print "Done\n";
print "\nLooks like I'm all done!\n";
close(SCRIPT);
close(LOG);
$dbh->disconnect;
sub getPerms
{
my ($obj) = $_[0];
my ($ret, @dat, $act, $cnt);
$sth = $dbh->prepare ("sp_helprotect '$obj'\n");
$sth->execute;
$cnt = 0;
while(@dat = $sth->fetchrow)
{
$act = 'to';
$act = 'from' if $dat[0] =~ /Revoke/;
print SCRIPT "$dat[2] $dat[3] on $obj $act $dat[1]\n";
++$cnt;
}
$sth->finish;
$cnt;
}
sub getObj
{
my ($objname, $obj) = @_;
my (@dat, @items, @vi, $found, $text);
$sth = $dbh->prepare (<<SQLEND
select distinct o.name, u.name, o.id
from dbo.sysobjects o, dbo.sysusers u,
dbo.sysprocedures p
where o.type = '$obj' and o.name like '$Getopt::Std::opt_t' and u.uid = o.uid
and o.id = p.id and p.status & 4096 != 4096
order by o.name
SQLEND
);
$sth->execute;
while((@dat = $sth->fetchrow))
{
push (@items, [ @dat ]); # and save it in a list
}
$sth->finish;
foreach (@items)
{
@vi = @$_;
$found = 0;
$sth = $dbh->prepare ("select text from dbo.syscomments where id = $vi[2]");
$sth->execute;
print SCRIPT
"/* $objname $vi[0], owner $vi[1] */\n";
while(($text) = $sth->fetchrow)
{
if(!$found && $vi[1] ne 'dbo')
{
++$found if($text =~ /$vi[1]/);
}
print SCRIPT $text;
}
$sth->finish;
print SCRIPT "\ngo\n";
if(!$found && $vi[1] ne 'dbo')
{
print "**Warning**\n$objname $vi[0] has owner $vi[1]\nbut this is not mentioned in the CREATE PROC statement!!\n";
print LOG "$objname $vi[0] (owner $vi[1])\n";
}
if ($obj eq 'V' || $obj eq 'P')
{
getPerms("$vi[0]") && print SCRIPT "go\n";
}
}
}
sub printKeys
{
print "Create sp_*key definitions...";
print SCRIPT "\n/* Now create the key definitions ...*/\n\n";
$sth = $dbh->prepare (<<SQLEND
select keytype = convert(char(10), v.name), object = object_name(k.id),
related_object = object_name(k.depid),
key1 = col_name(k.id, key1),
key2 = col_name(k.id, key2),
key3 = col_name(k.id, key3),
key4 = col_name(k.id, key4),
key5 = col_name(k.id, key5),
key6 = col_name(k.id, key6),
key7 = col_name(k.id, key7),
key8 = col_name(k.id, key8),
depkey1 = col_name(k.depid, key1),
depkey2 = col_name(k.depid, key2),
depkey3 = col_name(k.depid, key3),
depkey4 = col_name(k.depid, key4),
depkey5 = col_name(k.depid, key5),
depkey6 = col_name(k.depid, key6),
depkey7 = col_name(k.depid, key7),
depkey8 = col_name(k.depid, key8)
from dbo.syskeys k, master.dbo.spt_values v, dbo.sysobjects o
where k.type = v.number and v.type = 'K'
and k.id = o.id
and o.type != 'S'
and o.name like '$Getopt::Std::opt_t'
order by v.number, object, related_object
SQLEND
);
$sth->execute;
while((@dat = $sth->fetchrow)) {
if ($dat[0] eq "primary") {
print SCRIPT "sp_primarykey $dat[1],";
PrintCols (@dat[3..10]);
print SCRIPT "\ngo\n";
}
if ($dat[0] eq "foreign") {
print SCRIPT "sp_foreignkey $dat[1], $dat[2],";
PrintCols (@dat[11..18]);
print SCRIPT "\ngo\n";
}
if ($dat[0] eq "common") {
print SCRIPT "sp_commonkey $dat[1], $dat[2],";
PrintCols (@dat[3..10]);
print SCRIPT "\ngo\n";
}
}
$sth->finish;
print "done\n"
}
sub getComment
{
my ($objid) = @_;
my ($line, $text);
$sth = $dbh->prepare (
qq(select text from dbo.syscomments where id = $objid));
$sth->execute;
$text = "";
while(($line) = $sth->fetchrow)
{
$text = $text . $line;
}
$sth->finish;
return $text;
}
sub PrintCols
{
my ($col, $first);
$first = 1;
while ($col = shift (@_)) {
last if ($col eq '*');
print SCRIPT ", " if !$first;
$first = 0;
print SCRIPT "$col";
}
}
# Note: this is a recursive subroutine.
# If the current table references another that is in the list of
# tables to be dumped, and if that table has not yet been dumped,
# then DumpTable is called to dump it before proceeding
sub DumpTable
{
my ($tabref, @referers) = @_;
return if @$tabref[3] eq "Y";
my @nul = ('not null','null');
my (@dat, $dat, @col);
my (@refcols, @reflist, @field, $rule, $dflt, %rule, %dflt, $ddlrule, $ddldflt);
my ($refname, $first, $matchstring, $field, @constrids, $constrid);
my ($frgntabref);
my ($nultype);
# first, get any reference and ensure that dependent tables have already been
# created
$sth = $dbh->prepare (<<SQLEND
select isnull (r.frgndbname, '$Getopt::Std::opt_d'),
object_name (r.constrid),
object_name (r.reftabid, r.frgndbid),
user_name (o2.uid),
fokey1 = col_name (r.tableid, r.fokey1),
fokey2 = col_name (r.tableid, r.fokey2),
fokey3 = col_name (r.tableid, r.fokey3),
fokey4 = col_name (r.tableid, r.fokey4),
fokey5 = col_name (r.tableid, r.fokey5),
fokey6 = col_name (r.tableid, r.fokey6),
fokey7 = col_name (r.tableid, r.fokey7),
fokey8 = col_name (r.tableid, r.fokey8),
fokey9 = col_name (r.tableid, r.fokey9),
fokey10 = col_name (r.tableid, r.fokey10),
fokey11 = col_name (r.tableid, r.fokey11),
fokey12 = col_name (r.tableid, r.fokey12),
fokey13 = col_name (r.tableid, r.fokey13),
fokey14 = col_name (r.tableid, r.fokey14),
fokey15 = col_name (r.tableid, r.fokey15),
fokey16 = col_name (r.tableid, r.fokey16),
refkey1 = col_name (r.reftabid, r.refkey1),
refkey2 = col_name (r.reftabid, r.refkey2),
refkey3 = col_name (r.reftabid, r.refkey3),
refkey4 = col_name (r.reftabid, r.refkey4),
refkey5 = col_name (r.reftabid, r.refkey5),
refkey6 = col_name (r.reftabid, r.refkey6),
refkey7 = col_name (r.reftabid, r.refkey7),
refkey8 = col_name (r.reftabid, r.refkey8),
refkey9 = col_name (r.reftabid, r.refkey9),
refkey10 = col_name (r.reftabid, r.refkey10),
refkey11 = col_name (r.reftabid, r.refkey11),
refkey12 = col_name (r.reftabid, r.refkey12),
refkey13 = col_name (r.reftabid, r.refkey13),
refkey14 = col_name (r.reftabid, r.refkey14),
refkey15 = col_name (r.reftabid, r.refkey15),
refkey16 = col_name (r.reftabid, r.refkey16)
from dbo.sysreferences r, dbo.sysobjects o1, dbo.sysobjects o2
where r.tableid = o1.id
and r.pmrydbname is null
and o1.name = '@$tabref[0]'
and o1.uid = user_id ('@$tabref[1]')
and r.reftabid *= o2.id
SQLEND
);
$sth->execute;
while((@refcols = $sth->fetchrow))
{
push (@reflist, [ @refcols ]);
}
$sth->finish;
foreach (@reflist) {
@refcols = @$_;
# if the foreign table is in a foreign database or is not in
# our table list, then don't do any more than add it to the list
next if $refcols[0] ne $Getopt::Std::opt_d;
$refname = $refcols[3] . "." . $refcols[2];
next if not defined ($tables{$refname});
$frgntabref = $tables{$refname};
# otherwise check if it's already been dumped, if so, continue
next if @$frgntabref[3] eq "Y";
# make sure we aren't in a refernce loop by checking to see if this table is
# already in the heirarchy of refering tables that led to the current invocation
grep ($refname, @referers)
&& print SCRIPT "/* WARNING: circular foreign key reference to $refname */\n"
&& print LOG "@$tabref[1].@$tabref[0] in circular foreign key reference to $refname\n";
# so dump the referenced tables first
DumpTable ($frgntabref, @referers, $refname);
}
print "Creating table @$tabref[0], owner @$tabref[1]\n" if $Getopt::Std::opt_v;
print SCRIPT "/* Start of description of table @$tabref[1].@$tabref[0] */\n\n";
$sth = $dbh->prepare (<<SQLEND
select distinct Column_name = c.name,
Type = t.name,
Length = c.length,
Prec = c.prec,
Scale = c.scale,
Nulls = convert(bit, (c.status & 8)),
Default_name = object_name(c.cdefault),
Rule_name = object_name(c.domain),
Ident = convert(bit, (c.status & 0x80)),
Default_Ddl = isnull (d.status & 4096, 0),
Rule_Ddl = isnull (r.status & 4096, 0),
DefaultId = c.cdefault,
RuleId = c.domain
from dbo.syscolumns c, dbo.systypes t,
dbo.sysprocedures d, dbo.sysprocedures r
where c.id = @$tabref[2]
and c.usertype *= t.usertype
and c.cdefault *= d.id
and c.domain *= r.id
order by c.colid
SQLEND
);
$sth->execute;
undef(%rule);
undef(%dflt);
print SCRIPT "\n\nCREATE TABLE @$tabref[1].@$tabref[0] (\n";
$first = 1;
@col = ();
while (@field = $sth->fetchrow)
{
push @col, [ @field ];
}
$sth->finish;
foreach (@col) {
@field = @$_;
print SCRIPT ",\n" if !$first; # add a , and a \n if not first field in table
# get the declarative rule and default (if set)
if ($field[9] != 0) {
$ddldflt = getComment ($field[11]);
} else {
$ddldflt = "";
}
if ($field[10] != 0) {
$ddlrule = getComment ($field[12]);
} else {
$ddlrule = "";
}
# Check if its an identity column
if ($field[8] == 1) {
$nultype = "identity";
} else {
$nultype = $nul[$field[5]];
}
print SCRIPT "\t$field[0] \t$field[1]";
print SCRIPT "($field[2])" if $field[1] =~ /char|bin/;
print SCRIPT "($field[3],$field[4])" if $field[1] =~ /\bnumeric\b|\bdecimal\b/;
print SCRIPT " $ddldflt $nultype $ddlrule";
if (defined ($field[7])
&& ((!defined ($urule{$field[1]})) || $urule{$field[1]} ne $field[7])
&& ($field[10] == 0)) {
$rule{"@$tabref[0].$field[0]"} = $field[7];
}
if (defined ($field[6])
&& ((!defined ($udflt{$field[1]})) || $udflt{$field[1]} ne $field[6])
&& ($field[9] == 0)) {
$dflt{"@$tabref[0].$field[0]"} = $field[6];
}
$first = 0 if $first;
}
# references
foreach (@reflist) {
@refcols = @$_;
print SCRIPT ",";
$refname = $refcols[3] . "." . $refcols[2];
if ($refcols[0] ne $Getopt::Std::opt_d) {
print SCRIPT "\n/* The following reference is in database
** $refcols[0], edit the script to create the reference manually
";
print LOG "Reference for @$tabref[1].@$tabref[0] in foreign database\n\t";
$refname = $refcols[0] . "." . $refname;
}
print SCRIPT "\n\t";
$matchstring = substr($refcols[1], 0, 8) . "[_0-9][_0-9]*";
$refcols[1] !~ /$matchstring/
&& print SCRIPT "CONSTRAINT $refcols[1] ";
print SCRIPT "FOREIGN KEY (";
PrintCols (@refcols[4..19]);
print SCRIPT ") REFERENCES $refname (";
PrintCols (@refcols[20..35]);
print SCRIPT ")";
if ($refcols[0] ne $Getopt::Std::opt_d) {
print SCRIPT "*/";
}
}
# now get the indexes and keys...
#
print "Indexes for table @$tabref[1].@$tabref[0]\n" if $Getopt::Std::opt_v;
$sth = $dbh->prepare (<<SQLEND
select name, indid, status, status2,
key1 = index_col ('@$tabref[1].@$tabref[0]', indid, 1),
key2 = index_col ('@$tabref[1].@$tabref[0]', indid, 2),
key3 = index_col ('@$tabref[1].@$tabref[0]', indid, 3),
key4 = index_col ('@$tabref[1].@$tabref[0]', indid, 4),
key5 = index_col ('@$tabref[1].@$tabref[0]', indid, 5),
key6 = index_col ('@$tabref[1].@$tabref[0]', indid, 6),
key7 = index_col ('@$tabref[1].@$tabref[0]', indid, 7),
key8 = index_col ('@$tabref[1].@$tabref[0]', indid, 8),
key9 = index_col ('@$tabref[1].@$tabref[0]', indid, 9),
key10 = index_col ('@$tabref[1].@$tabref[0]', indid, 10),
key11 = index_col ('@$tabref[1].@$tabref[0]', indid, 11),
key12 = index_col ('@$tabref[1].@$tabref[0]', indid, 12),
key13 = index_col ('@$tabref[1].@$tabref[0]', indid, 13),
key14 = index_col ('@$tabref[1].@$tabref[0]', indid, 14),
key15 = index_col ('@$tabref[1].@$tabref[0]', indid, 15),
key16 = index_col ('@$tabref[1].@$tabref[0]', indid, 16)
from dbo.sysindexes
where id = object_id ('@$tabref[1].@$tabref[0]')
and indid between 1 and 254
SQLEND
);
$sth->execute;
@col = ();
while((@field = $sth->fetchrow))
{
# if this is a key or unique constraint, print out the details
# otherwise buffer it up to print as an index afterwards
if ($field[3] & 2) {
print (SCRIPT ",\n\t");
print SCRIPT "CONSTRAINT $field[0] " unless ($field[3] & 8);
if ($field[2] & 2048) {
print SCRIPT "PRIMARY KEY ";
print SCRIPT "NONCLUSTERED " if ($field[1] != 1);
} else {
print SCRIPT "UNIQUE ";
print SCRIPT "CLUSTERED " if ($field[1] == 1);
}
print SCRIPT "(";
PrintCols (@field[4..19]);
print SCRIPT ")";
} else {
push @col, [ @field ];
}
}
$sth->finish;
# Now do the table level check constraints
@constrids = ();
$sth = $dbh->prepare (<<SQLEND
select constrid from dbo.sysconstraints
where tableid = object_id ('@$tabref[1].@$tabref[0]')
and status & 128 = 128
and colid = 0
SQLEND
);
$sth->execute;
while (@field = $sth->fetchrow) {
@constrids = (@constrids, $field[0]);
}
$sth->finish;
foreach $constrid (@constrids) {
print SCRIPT ",\n\t" . getComment ($constrid);
}
print SCRIPT "\n)\ngo\n"; # end of CREATE TABLE
foreach (@col) { # now print the indexes
@field = @$_;
print SCRIPT "\nCREATE ";
print SCRIPT "UNIQUE " if $field[2] & 2;
print SCRIPT "CLUSTERED " if $field[1] == 1;
print SCRIPT "INDEX $field[0]\n";
print SCRIPT "ON @$tabref[1].@$tabref[0] (";
PrintCols (@field[4..19]);
print SCRIPT ")";
$first = 1;
if ($field[2] & 64) {
print SCRIPT " WITH ALLOW_DUP_ROW";
$first = 0;
}
if ($field[2] & 1) {
print SCRIPT (($first == 0) ? ", " : " WITH ") . "IGNORE_DUP_KEY";
$first = 0;
}
if ($field[2] & 4) {
print SCRIPT (($first == 0) ? ", " : " WITH ") . "IGNORE_DUP_ROW";
$first = 0;
}
print SCRIPT "\ngo\n";
}
getPerms("@$tabref[1].@$tabref[0]") && print SCRIPT "go\n";
print "Bind rules & defaults to columns...\n" if $Getopt::Std::opt_v;
print SCRIPT "/* Bind rules & defaults to columns... */\n\n";
if(@$tabref[1] ne 'dbo' && (keys(%dflt) || keys(%rule)))
{
print SCRIPT "/* The owner of the table is @$tabref[1].
* I can't bind the rules/defaults to a table of which I am not the owner.
* The procedures below will have to be run manualy by user @$tabref[1].
*/";
print LOG "Defaults/Rules for @$tabref[1].@$tabref[0] could not be bound\n";
}
while(($dat, $dflt)=each(%dflt))
{
print SCRIPT "/* " if @$tabref[1] ne 'dbo';
print SCRIPT "sp_bindefault $dflt, '$dat'";
if(@$tabref[1] ne 'dbo')
{
print SCRIPT " */\n";
}
else
{
print SCRIPT "\ngo\n";
}
}
while(($dat, $rule) = each(%rule))
{
print SCRIPT "/* " if @$tabref[1] ne 'dbo';
print SCRIPT "sp_bindrule $rule, '$dat'";
if(@$tabref[1] ne 'dbo')
{
print SCRIPT " */\n";
}
else
{
print SCRIPT "\ngo\n";
}
}
print SCRIPT "\n/* End of description of table @$tabref[1].@$tabref[0] */\n";
@$tabref[3] = "Y";
}