head	1.4;
access;
symbols
	TIGRIS_1_1_0RC2:1.3.2.1
	TIGRIS_1_1_0RC1:1.3.2.1
	TIGRIS_1_1:1.3.2.1.0.2
	TIGRIS_1_0_8:1.3.2.1
	TIGRIS_1_0_8RC3:1.3.2.1
	TIGRIS_1_0_8RC2:1.3.2.1
	TIGRIS_1_0_8RC1:1.3.2.1
	TIGRIS_1_0_7:1.3.2.1
	TIGRIS_1_0_7RC3:1.3.2.1
	TIGRIS_1_0_7RC2:1.3.2.1
	TIGRIS_1_0_7RC1:1.3.2.1
	TIGRIS_1_0_6:1.3.2.1
	TIGRIS_1_0_6RC5:1.3.2.1
	TIGRIS_1_0_6RC4:1.3.2.1
	TIGRIS_1_0_6RC3:1.3.2.1
	TIGRIS_1_0_6RC2:1.3.2.1
	TIGRIS_1_0_6RC1:1.3.2.1
	TIGRIS_1_0_5:1.3.2.1
	TIGRIS_1_0_5RC6:1.3.2.1
	TIGRIS_1_0_5RC5:1.3.2.1
	TIGRIS_1_0_5RC4:1.3.2.1
	TIGRIS_1_0_5RC3:1.3.2.1
	TIGRIS_1_0_5RC2:1.3.2.1
	TIGRIS_1_0_5RC1:1.3.2.1
	TIGRIS_1_0_4:1.3.2.1
	TIGRIS_1_0:1.3.0.2;
locks; strict;
comment	@# @;


1.4
date	2001.08.14.17.24.54;	author kmaples;	state Exp;
branches;
next	1.3;

1.3
date	2001.04.26.17.40.51;	author kmaples;	state Exp;
branches
	1.3.2.1;
next	1.2;

1.2
date	2001.04.26.17.28.28;	author kmaples;	state Exp;
branches;
next	1.1;

1.1
date	2001.04.26.16.46.31;	author kmaples;	state Exp;
branches;
next	;

1.3.2.1
date	2001.05.02.19.54.31;	author kmaples;	state Exp;
branches;
next	;


desc
@@


1.4
log
@Issue number: 4224
Warn the user if s/he tries to compare something to itself.
@
text
@#!/usr/bin/perl -w
# $Id: compare_dbs.pl,v 1.3 2001/04/26 17:40:51 kmaples Exp $

use diagnostics;
use DBI;

BEGIN {
    unshift(@@INC, "$ENV{SANDBOX}/scripts");
}
use HelmDB;

# Databases to compare:

my $DB_A = shift(@@ARGV);
my $DB_B = shift(@@ARGV) || '';

unless($DB_A){
    print "No database specified!\n\n";
    print usage(); 
    exit;   
}
if($DB_A eq $DB_B){
	print "Can't compare the data to itself!\n\n";
	print usage();
	exit;
}

$DB_B ||= $DB_A;

my $DBPW  = $ENV{DATABASE_ADMIN_PASSWORD};
my $DBUSR = $ENV{DATABASE_ADMIN_USER};

unless($DBPW && $DBUSR){
    print "Insufficient ENV info to talk to DB.  Try sourcing env.sh.\n";
    exit;   
}

my @@db_a_schema = ();
my @@db_b_schema = ();
my $compare_different_dbs = 0;
my $current_table = '';
my %bad_tables = ();
my (%schema_a, %schema_b);

my @@ERR;

my $statement;
my $select;
my $ret;

if($DB_A ne $DB_B){ 
    print "Comparing $DB_A to $DB_B\n";
    $compare_different_dbs = 1;

    @@db_a_schema = get_schema($DB_A);
    %schema_a = parse_schema_dump(@@db_a_schema); 
    @@db_b_schema = get_schema($DB_B);
    %schema_b = parse_schema_dump(@@db_b_schema);
    
} else {
    print "Checking data in $DB_A\n";
    @@db_a_schema = get_schema($DB_A, 'db');
    %schema_a = parse_schema_dump(@@db_a_schema);

}

# Perform either the comparison, or the data validation:
if($compare_different_dbs){
    foreach(keys(%schema_a)){
        my $table = $_;
        
        # Check that there's even such a table there:
        if(!$schema_b{$table}){
            put_error("Table $table missing from $DB_B");
        } else {
            foreach(keys(%{ $schema_a{$table} })){
                my ($col, $def)   = ($_, $schema_a{$table}->{$_});
                my $defb          = $schema_b{$table}->{$_};
                
                my $check_def = 0;
                
                # Check that there's a column there:
                if(!$defb){
                    put_error("Table $table in $DB_B lacks column $col");
                } else {
                    # Check that the defs are the same
                    unless($def eq $defb){
                        put_error("'$table.$col' in $DB_B does not match $DB_A:");
                        put_error("  $DB_A: $def");
                        put_error("  $DB_B: $defb");
                    }
                }
            }
        }
    }
} else {
    # This is the only case for which we need to talk
    # to the database, so make a connection here - note
    # that we're connecting to 'DB_B' (though they should
    # be one and the same here), lest the two-argument form
    # of this script ever be expanded to include this test:
    my $dbh = HelmDB::connect(
    $DB_B, $ENV{DATABASE_ADMIN_USER}, $ENV{DATABASE_ADMIN_PASSWORD});
   
    while(my ($table, $ref) = (each %schema_a)){
        foreach(keys %{$ref}){
            my ($col, $def) = ($_, $ref->{$_});
            my @@clauses     = ();
            my $enumvals = '';
            
#           print "table: $table\n";
#           print "col:   $col\n";
#           print "def:   $def\n";
            
            # Check for verifiable data:
            if($def =~ m/enum\(([^)]+)\)/i){
                $enumvals = $1;
                push(@@clauses, qq[  $col NOT IN ($enumvals)\n]);
            }   
            if($def =~ m/not\s+null/i){
                push(@@clauses, qq[  $col = NULL\n]);
            }
            # 3. query database ... IF some usable condition applies:
            if(@@clauses){
                $statement = qq[SELECT COUNT($col) FROM $table WHERE \n]; 
                $statement .= join(' OR ', @@clauses);
        
                $select    = $dbh->prepare($statement);
                $ret       = $select->execute;
                $count     = ($select->fetchrow_array)[0];
            
                if($count){
                    $bad_tables{$table} = { $col => $count};    
                }
            }
        }   
    }
    $dbh->disconnect;
}   
# Two routines for errors; these need to be consolidated 
# as usage requires:
if(@@ERR){
    print "The following differences were found:\n\n";
    foreach(@@ERR){ print "  $_\n";} 
}
if(%bad_tables){
    print "The following tables in $DB_A were found to have data\n";
    print "inconsistent with the database's schema:\n\n";
    while(my($k, $v) = each(%bad_tables)){
        print "  table $k:\n";
        while(my($x, $y) = each(%{ $v })){
            print "    column '$x':  $y rows\n";    
        }   
    }   
}

print "\n";

#---------------------
sub put_error {
#---------------------
    my $err = shift;
    push(@@ERR, $err);   
}
#---------------------
sub get_schema {
#---------------------
    my $dbs     = shift;
    my $forcedb = shift; # Force this arg to be a db
    
    my @@lines = ();
    
    if(-e $dbs && !$forcedb){
        open(F, $dbs) or die "Unable to open $dbs for reading: $!\n";
        @@lines = <F>;
        close F;    
    } else {
        @@lines = qx(mysqldump -u$DBUSR -p$DBPW --no-data $dbs );    
    }
    return(@@lines);

}
#---------------------
sub parse_schema_dump {
#---------------------
    # my %schema = parse_schema_dump(@@db_dump);
    # $col_def  = $schema{table}->{col}
    
    my %schema = ();
    my @@dump = @@_;
    my $current_table = '';
    
    while($_ = shift(@@dump)){
        # strip leading and trailing whitespace:
        s/^\s+//;
        s/\s+$//;
        # skip the irrelevant:
        next if m/^#/;
        next if m/^(\s+)?$/;
        
        if(m/^\s*\);\s*$/){ # Table def. termination
            next;   
        }
        if(m/CREATE\s+TABLE\s+(\w+)\s*\(/i){
            $current_table = $1;           
#            print "current table is $current_table\n";
            shift;  # Move on to the next line
        }
        # grab any key info first:
        if(m/^(PRIMARY KEY|(KEY|UNIQUE)\s+\S+)([^,]*),?$/i){
            # Keyname, followed by key def. - e.g.,
            # PRIMARY KEY = (field)
            # KEY name    = (field(s))
            # UNIQUE name = (field(s))
            $schema{$current_table}->{$1} = $3;
            next;
        }
        if(m/^(\w+)\s+(.*),(\s+)?$/){
#           print "  current col: $1\n";
#           print "  current def: $2\n";
            $schema{$current_table}->{$1} = $2;
        }
    } 
    # DEBUG
#    foreach my $key (keys %schema){
#       print "table $key\n";
#       foreach(keys %{$schema{$key}}){
#           my ($n, $v) = ($_ , $schema{$key}->{$_});
#           print "  $_  =  $schema{$key}->{$_}\n"; 
#       }   
#    }       
    return(%schema);
}
sub usage {
	my $text;

    $text .=  "Usage: \n";
    $text .=  "  compare_dbs.pl {source_db} {target_db}\n";
    $text .=  "  compare_dbs.pl {database}\n\n";
    $text .=  "Displays the elements present in source and missing\n";
    $text .=  "from target, or checks the data in the database against\n";
    $text .=  "it's own schema (empty values, enums, etc.).\n\n";
    $text .=  "In two-argument form, either source or target may be\n";
    $text .=  "a 'mysqldump --no-data' file, in which case the file";
    $text .=  "will be read in and compared, rather than the database.\n\n";
	
	return $text;

}


__END__



@


1.3
log
@Accidentally removed the name and password in the cleanup; restoring
@
text
@d2 1
a2 1
# $Id: compare_dbs.pl,v 1.1 2001/04/26 16:46:31 kmaples Exp $
d15 1
a15 1
my $DB_B = shift(@@ARGV) || $DB_A;
d19 1
a19 10
    print "Usage: \n";
    print "  compare_dbs.pl {source_db} {target_db}\n";
    print "  compare_dbs.pl {database}\n\n";
    print "Displays the elements present in source and missing\n";
    print "from target, or checks the data in the database against\n";
    print "it's own schema (empty values, enums, etc.).\n\n";
    print "In two-argument form, either source or target may be\n";
    print "a 'mysqldump --no-data' file, in which case the file";
    print "will be read in and compared, rather than the database.\n\n";
    
d22 7
d234 2
d237 13
@


1.3.2.1
log
@Modified migration scripts to change the bugs@@ user to issues@@; added a script
which attempts to reconcile existing helm accounts with older issuezilla
accounts upon upgrade from versions prior to 0.8.4; removed the sql statement
which attempted a brute-force transformation of user accounts in favor of
the aforementioned script; added data validation tools in helm/tests; added
the shared perl db library that these scripts use (HelmDB.pm) in previous
commit.
@
text
@d2 1
a2 1
# $Id: compare_dbs.pl,v 1.3 2001/04/26 17:40:51 kmaples Exp $
@


1.2
log
@Cleaned up code a bit
@
text
@d32 8
@


1.1
log
@moved the data validation scripts under the test/ dir.
@
text
@d2 1
a2 1
# $Id: compare_dbs.pl,v 1.2 2001/04/17 19:20:25 kmaples Exp $
d5 6
d25 3
a27 3
    print "Either source or target may be a 'mysqldump --no-data'\n";
    print "file, in which case the file will be read in and compared,\n";
    print "rather than the database.\n\n";
a31 25
use DBI;

# Stuff grabbed from env.sh:

my $DBPW  = $ENV{DATABASE_ADMIN_PASSWORD};
my $DBUSR = $ENV{DATABASE_ADMIN_USER};
my $DBHOST= $ENV{DATABASE_HOST};
my $DBPORT= $ENV{DATABASE_PORT};

unless($DBPW && $DBUSR && $DBHOST && $DBPORT){
    print "Insufficient ENV info to talk to DB.  Try sourcing env.sh.\n";
    exit;   
}

# Here we get a connection to $DB_B, since we'll be comparing 
# it to the schema defined in $DB_A:
my $dbc  = join(':','DBI','mysql',$DB_B, $DBHOST, $DBPORT);
my $CONN = DBI->connect($dbc, $DBUSR, $DBPW);

# Check for a good connection:
unless( $CONN =~ m/HASH/){
    print "No connection to database: $!\n";
    exit(1);
}

a44 7

#print "Getting sqldump of $DB_A ... \n";
@@db_a_schema = get_schema($DB_A);
#print "Parsing $DB_A schema ... \n";
%schema_a = parse_schema_dump(@@db_a_schema);


d48 3
a50 2
    
#    print "Getting sqldump of $DB_B ... \n";
a51 1
#    print "Parsing $DB_B schema ... \n";
d53 1
d56 3
d61 1
a61 1
# Perform either the comparison, or the data validatio:
d91 8
d122 1
a122 1
                $select    = $CONN->prepare($statement);
d132 1
a152 3
$select->finish() if $select;
$CONN->disconnect;

d162 3
a164 1
    my $dbs   = shift;
d167 1
a167 1
    if(-e $dbs){
@

