sub get_table_CRC {
my $dbh = shift;
my $tablename = shift;
my $fields = get_fields($dbh, $tablename);
my $check_table = qq[
SELECT
COUNT(*) AS cnt,
CONCAT(SUM(CONV(
SUBSTRING(\@CRC:=MD5(
CONCAT_WS('/##/',$fields)),1,8),16,10 )),
SUM(CONV(SUBSTRING(\@CRC, 9,8),16,10)),
SUM(CONV(SUBSTRING(\@CRC,17,8),16,10)),
SUM(CONV(SUBSTRING(\@CRC,25,8),16,10))
) AS sig
FROM
$tablename
];
# uncomment the following line to see the full query
# print $check_table,$/;
my ($count, $crc);
eval { ($count, $crc) = $dbh->selectrow_array($check_table)};
if ($@)
{
return undef;
}
return [$count, $crc];
}
####
sub get_fields
{
my ($dbh, $tablename) = @_;
my $sth = $dbh->prepare(qq[describe $tablename]);
$sth->execute();
my @fields=();
while (my $row = $sth->fetchrow_hashref())
{
my $field ="`$row->{Field}`"; # backticks
# if the field is nullable,
# then a COALESCE function is used
# to prevent the whole CONCAT from becoming NULL
if (lc $row->{Null} eq 'yes')
{
$field = qq[COALESCE($field,"#NULL#")];
}
push @fields, $field;
}
return join ",", @fields;
}
##
##
#!/usr/bin/perl -w
use strict;
use DBI;
# for this test, we create the database handlers directly
# in the script
my $dbh1 = DBI->connect('dbi:mysql:test;host=localhost',
'localuser', 'localpassword', {RaiseError => 1});
my $dbh2 = DBI->connect('dbi:mysql:test;host=192.168.2.33;port=13330',
'remoteuser', 'remotepassword', {RaiseError => 1});
# this is the table to be created in both hosts
my $tablename = 'testcrc';
my $create =
qq{create table if not exists $tablename
(i int not null, j int, a char(1), b float )};
my ($table_exists) = $dbh1->selectrow_array(
qq{SHOW TABLES LIKE '$tablename'});
if ($table_exists)
{
# table exists. Let's make a tiny change
$dbh1->do(qq{update $tablename set j = j-1 where i = 50});
}
else # table does not exists. Create and populate
{
# create both tables
$dbh1->do($create);
$dbh2->do($create);
my $insert = qq{insert into $tablename values (?, ?, ?, ?)};
my $sth1 = $dbh1->prepare($insert);
my $sth2 = $dbh2->prepare($insert);
# populates both tables with the same values
for ( 1 .. 100 )
{
$sth1->execute($_, $_ * 100, chr(ord('A') + $_), 1 / 3 );
$sth2->execute($_, $_ * 100, chr(ord('A') + $_), 1 / 3 );
}
}
my %probes;
# gets the local table record count and CRC
$probes{'local'} = get_table_CRC($dbh1, $tablename)
or die "wrong info: $DBI::errstr\n";
# gets the remote table record count and CRC
$probes{'remote'} = get_table_CRC($dbh2, $tablename)
or die "wrong info: $DBI::errstr\n";
# Checks the result and displays
print "LOCAL : @{$probes{'local'}}\nREMOTE: @{$probes{'remote'}}\n";
if (
($probes{'local'}->[0] != $probes{'remote'}->[0])
or
($probes{'local'}->[1] ne $probes{'remote'}->[1])
)
{
print "there are differences\n";
}
else
{
print "NO DIFFERENCES\n";
}