Re-update modules in pt-table-sync and pt-table-checksum but keep old SchemaIterator.

This commit is contained in:
Daniel Nichter
2011-07-13 17:13:11 -06:00
parent ea0b8c3d5a
commit c78beba647
2 changed files with 354 additions and 444 deletions

View File

@@ -9,26 +9,26 @@ use warnings FATAL => 'all';
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
# ###########################################################################
# TableParser package 7156
# TableParser package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/TableParser.pm
# trunk/common/t/TableParser.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/TableParser.pm
# t/lib/TableParser.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package TableParser;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Quotekeys = 0;
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(Quoter);
@@ -319,6 +319,7 @@ sub get_keys {
sub get_fks {
my ( $self, $ddl, $opts ) = @_;
my $q = $self->{Quoter};
my $fks = {};
foreach my $fk (
@@ -328,17 +329,22 @@ sub get_fks {
my ( $cols ) = $fk =~ m/FOREIGN KEY \(([^\)]+)\)/;
my ( $parent, $parent_cols ) = $fk =~ m/REFERENCES (\S+) \(([^\)]+)\)/;
my ($db, $tbl) = $q->split_unquote($parent, $opts->{database});
my %parent_tbl = (tbl => $tbl);
$parent_tbl{db} = $db if $db;
if ( $parent !~ m/\./ && $opts->{database} ) {
$parent = "`$opts->{database}`.$parent";
$parent = $q->quote($opts->{database}) . ".$parent";
}
$fks->{$name} = {
name => $name,
colnames => $cols,
cols => [ map { s/[ `]+//g; $_; } split(',', $cols) ],
parent_tbl => $parent,
parent_colnames=> $parent_cols,
parent_tbl => \%parent_tbl,
parent_tblname => $parent,
parent_cols => [ map { s/[ `]+//g; $_; } split(',', $parent_cols) ],
parent_colnames=> $parent_cols,
ddl => $fk,
};
}
@@ -398,28 +404,29 @@ sub _d {
}
1;
}
# ###########################################################################
# End TableParser package
# ###########################################################################
# ###########################################################################
# TableChecksum package 7080
# TableChecksum package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/TableChecksum.pm
# trunk/common/t/TableChecksum.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/TableChecksum.pm
# t/lib/TableChecksum.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package TableChecksum;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use List::Util qw(max);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use List::Util qw(max);
our %ALGOS = (
CHECKSUM => { pref => 0, hash => 0 },
BIT_XOR => { pref => 2, hash => 1 },
@@ -780,28 +787,28 @@ sub _d {
}
1;
}
# ###########################################################################
# End TableChecksum package
# ###########################################################################
# ###########################################################################
# OptionParser package 7102
# OptionParser package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/OptionParser.pm
# trunk/common/t/OptionParser.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/OptionParser.pm
# t/lib/OptionParser.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package OptionParser;
use strict;
use warnings FATAL => 'all';
use List::Util qw(max);
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use List::Util qw(max);
use Getopt::Long;
my $POD_link_re = '[LC]<"?([^">]+)"?>';
@@ -851,9 +858,9 @@ sub new {
defaults_to => {}, # rule: opt defaults to value of other opt
DSNParser => undef,
default_files => [
"/etc/maatkit/maatkit.conf",
"/etc/maatkit/$program_name.conf",
"$home/.maatkit.conf",
"/etc/percona-toolkit/percona-toolkit.conf",
"/etc/percona-toolkit/$program_name.conf",
"$home/.percona-toolkit.conf",
"$home/.$program_name.conf",
],
types => {
@@ -1801,20 +1808,20 @@ sub _d {
}
1;
}
# ###########################################################################
# End OptionParser package
# ###########################################################################
# ###########################################################################
# DSNParser package 7388
# DSNParser package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/DSNParser.pm
# trunk/common/t/DSNParser.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/DSNParser.pm
# t/lib/DSNParser.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package DSNParser;
use strict;
@@ -1831,7 +1838,6 @@ eval {
};
my $have_dbi = $EVAL_ERROR ? 0 : 1;
sub new {
my ( $class, %args ) = @_;
foreach my $arg ( qw(opts) ) {
@@ -2028,8 +2034,8 @@ sub get_dbh {
my $dbh;
my $tries = 2;
while ( !$dbh && $tries-- ) {
MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, ' {',
join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ), '}');
MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
eval {
$dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
@@ -2158,26 +2164,25 @@ sub _d {
}
1;
}
# ###########################################################################
# End DSNParser package
# ###########################################################################
# ###########################################################################
# VersionParser package 6667
# VersionParser package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/VersionParser.pm
# trunk/common/t/VersionParser.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/VersionParser.pm
# t/lib/VersionParser.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package VersionParser;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
@@ -2242,26 +2247,25 @@ sub _d {
}
1;
}
# ###########################################################################
# End VersionParser package
# ###########################################################################
# ###########################################################################
# MySQLDump package 6345
# MySQLDump package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/MySQLDump.pm
# trunk/common/t/MySQLDump.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/MySQLDump.pm
# t/lib/MySQLDump.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package MySQLDump;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
( our $before = <<'EOF') =~ s/^ //gm;
@@ -2548,20 +2552,20 @@ sub _d {
}
1;
}
# ###########################################################################
# End MySQLDump package
# ###########################################################################
# ###########################################################################
# TableChunker package 7169
# TableChunker package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/TableChunker.pm
# trunk/common/t/TableChunker.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/TableChunker.pm
# t/lib/TableChunker.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package TableChunker;
use strict;
@@ -3481,26 +3485,25 @@ sub _d {
}
1;
}
# ###########################################################################
# End TableChunker package
# ###########################################################################
# ###########################################################################
# Quoter package 6850
# Quoter package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/Quoter.pm
# trunk/common/t/Quoter.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/Quoter.pm
# t/lib/Quoter.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package Quoter;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
@@ -3559,7 +3562,7 @@ sub join_quote {
}
1;
}
# ###########################################################################
# End Quoter package
# ###########################################################################
@@ -4178,23 +4181,22 @@ sub _d {
# ###########################################################################
# ###########################################################################
# Daemon package 6255
# Daemon package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/Daemon.pm
# trunk/common/t/Daemon.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/Daemon.pm
# t/lib/Daemon.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package Daemon;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use POSIX qw(setsid);
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
my ( $class, %args ) = @_;
@@ -4359,18 +4361,14 @@ sub _d {
}
1;
}
# ###########################################################################
# End Daemon package
# ###########################################################################
# ###########################################################################
# SchemaIterator package 7512
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/SchemaIterator.pm
# trunk/common/t/SchemaIterator.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# SchemaIterator r7512
# Don't update this package!
# ###########################################################################
package SchemaIterator;
@@ -4740,13 +4738,14 @@ sub _d {
# ###########################################################################
# ###########################################################################
# Retry package 7473
# Retry package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/Retry.pm
# trunk/common/t/Retry.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/Retry.pm
# t/lib/Retry.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package Retry;
use strict;
@@ -4817,30 +4816,25 @@ sub _d {
}
1;
}
# ###########################################################################
# End Retry package
# ###########################################################################
# ###########################################################################
# Progress package 7096
# Progress package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the SVN repository at,
# trunk/common/Progress.pm
# trunk/common/t/Progress.t
# See http://code.google.com/p/maatkit/wiki/Developers for more information.
# with comments and its test file can be found in the Bazaar repository at,
# lib/Progress.pm
# t/lib/Progress.t
# See https://launchpad.net/percona-toolkit for more information.
# ###########################################################################
{
package Progress;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Quotekeys = 0;
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
@@ -4963,7 +4957,7 @@ sub _d {
}
1;
}
# ###########################################################################
# End Progress package
# ###########################################################################
@@ -6584,7 +6578,7 @@ sub do_tbl_replicate {
foreach my $warning ( @$warnings ) {
if ( $warning->{message} =~ m/Data truncated for column 'boundaries'/ ) {
_d("Warning: WHERE clause too large for boundaries column; ",
"mk-table-sync may fail; value:", $where);
"pt-table-sync may fail; value:", $where);
}
elsif ( ($warning->{code} || 0) == 1592 ) {
# Error: 1592 SQLSTATE: HY000 (ER_BINLOG_UNSAFE_STATEMENT)
@@ -7124,7 +7118,7 @@ Or,
Or,
pt-table-checksum host1 host2 ... hostN | mk-checksum-filter
pt-table-checksum host1 host2 ... hostN | pt-checksum-filter
See L<"SPECIFYING HOSTS"> for more on the syntax of the host arguments.
@@ -7173,7 +7167,7 @@ on the same server, just checksum both databases:
pt-table-checksum --databases db1,db2
You can then use L<mk-checksum-filter> to compare the results in both databases
You can then use L<pt-checksum-filter> to compare the results in both databases
easily.
pt-table-checksum examines table structure only on the first host specified,
@@ -7403,7 +7397,7 @@ Output is unsorted, though all lines for one table should be output together.
For speed, all checksums are done in parallel (as much as possible) and may
complete out of the order in which they were started. You might want to run
them through another script or command-line utility to make sure they are in the
order you want. If you pipe the output through L<mk-checksum-filter>, you
order you want. If you pipe the output through L<pt-checksum-filter>, you
can sort the output and/or avoid seeing output about tables that have no
differences.
@@ -8167,8 +8161,8 @@ L<"--replicate-check"> option, pt-table-checksum can run the query for you to
make it even easier. See L<"CONSISTENT CHECKSUMS"> for details.
If you find tables that have differences, you can use the chunk boundaries in a
WHERE clause with L<mk-table-sync> to help repair them more efficiently. See
L<mk-table-sync> for details.
WHERE clause with L<pt-table-sync> to help repair them more efficiently. See
L<pt-table-sync> for details.
The table must have at least these columns: db, tbl, chunk, boundaries,
this_crc, master_crc, this_cnt, master_cnt. The table may be named anything you
@@ -8597,7 +8591,7 @@ These DSN options are used to create a DSN. Each option is given like
C<option=value>. The options are case-sensitive, so P and p are not the
same option. There cannot be whitespace before or after the C<=> and
if the value contains whitespace it must be quoted. DSN options are
comma-separated. See the L<maatkit> manpage for full details.
comma-separated. See the L<percona-toolkit> manpage for full details.
=over

View File

@@ -6587,376 +6587,292 @@ sub _d {
# ###########################################################################
# ###########################################################################
# SchemaIterator package
# This package is a copy without comments from the original. The original
# with comments and its test file can be found in the Bazaar repository at,
# lib/SchemaIterator.pm
# t/lib/SchemaIterator.t
# See https://launchpad.net/percona-toolkit for more information.
# SchemaIterator r7141
# Don't update this package!
# ###########################################################################
{
package SchemaIterator;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
use English qw(-no_match_vars);
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Quotekeys = 0;
my $open_comment = qr{/\*!\d{5} };
my $tbl_name = qr{
CREATE\s+
(?:TEMPORARY\s+)?
TABLE\s+
(?:IF NOT EXISTS\s+)?
([^\(]+)
}x;
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser Quoter);
foreach my $arg ( @required_args ) {
foreach my $arg ( qw(Quoter) ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($file_itr, $dbh) = @args{qw(file_itr dbh)};
die "I need either a dbh or file_itr argument"
if (!$dbh && !$file_itr) || ($dbh && $file_itr);
my $self = {
%args,
filters => _make_filters(%args),
filter => undef,
dbs => [],
};
return bless $self, $class;
}
sub _make_filters {
my ( %args ) = @_;
my @required_args = qw(OptionParser Quoter);
sub make_filter {
my ( $self, $o ) = @_;
my @lines = (
'sub {',
' my ( $dbh, $db, $tbl ) = @_;',
' my $engine = undef;',
);
my @permit_dbs = _make_filter('unless', '$db', $o->get('databases'))
if $o->has('databases');
my @reject_dbs = _make_filter('if', '$db', $o->get('ignore-databases'))
if $o->has('ignore-databases');
my @dbs_regex;
if ( $o->has('databases-regex') && (my $p = $o->get('databases-regex')) ) {
push @dbs_regex, " return 0 unless \$db && (\$db =~ m/$p/o);";
}
my @reject_dbs_regex;
if ( $o->has('ignore-databases-regex')
&& (my $p = $o->get('ignore-databases-regex')) ) {
push @reject_dbs_regex, " return 0 if \$db && (\$db =~ m/$p/o);";
}
if ( @permit_dbs || @reject_dbs || @dbs_regex || @reject_dbs_regex ) {
push @lines,
' if ( $db ) {',
(@permit_dbs ? @permit_dbs : ()),
(@reject_dbs ? @reject_dbs : ()),
(@dbs_regex ? @dbs_regex : ()),
(@reject_dbs_regex ? @reject_dbs_regex : ()),
' }';
}
if ( $o->has('tables') || $o->has('ignore-tables')
|| $o->has('ignore-tables-regex') ) {
my $have_qtbl = 0;
my $have_only_qtbls = 0;
my %qtbls;
my @permit_tbls;
my @permit_qtbls;
my %permit_qtbls;
if ( $o->get('tables') ) {
my %tbls;
map {
if ( $_ =~ m/\./ ) {
$permit_qtbls{$_} = 1;
}
else {
$tbls{$_} = 1;
}
} keys %{ $o->get('tables') };
@permit_tbls = _make_filter('unless', '$tbl', \%tbls);
@permit_qtbls = _make_filter('unless', '$qtbl', \%permit_qtbls);
if ( @permit_qtbls ) {
push @lines,
' my $qtbl = ($db ? "$db." : "") . ($tbl ? $tbl : "");';
$have_qtbl = 1;
}
}
my @reject_tbls;
my @reject_qtbls;
my %reject_qtbls;
if ( $o->get('ignore-tables') ) {
my %tbls;
map {
if ( $_ =~ m/\./ ) {
$reject_qtbls{$_} = 1;
}
else {
$tbls{$_} = 1;
}
} keys %{ $o->get('ignore-tables') };
@reject_tbls= _make_filter('if', '$tbl', \%tbls);
@reject_qtbls = _make_filter('if', '$qtbl', \%reject_qtbls);
if ( @reject_qtbls && !$have_qtbl ) {
push @lines,
' my $qtbl = ($db ? "$db." : "") . ($tbl ? $tbl : "");';
}
}
if ( keys %permit_qtbls && !@permit_dbs ) {
my $dbs = {};
map {
my ($db, undef) = split(/\./, $_);
$dbs->{$db} = 1;
} keys %permit_qtbls;
MKDEBUG && _d('Adding restriction "--databases',
(join(',', keys %$dbs) . '"'));
if ( keys %$dbs ) {
$o->set('databases', $dbs);
return $self->make_filter($o);
}
}
my @tbls_regex;
if ( $o->has('tables-regex') && (my $p = $o->get('tables-regex')) ) {
push @tbls_regex, " return 0 unless \$tbl && (\$tbl =~ m/$p/o);";
}
my @reject_tbls_regex;
if ( $o->has('ignore-tables-regex')
&& (my $p = $o->get('ignore-tables-regex')) ) {
push @reject_tbls_regex,
" return 0 if \$tbl && (\$tbl =~ m/$p/o);";
}
my @get_eng;
my @permit_engs;
my @reject_engs;
if ( ($o->has('engines') && $o->get('engines'))
|| ($o->has('ignore-engines') && $o->get('ignore-engines')) ) {
push @get_eng,
' my $sql = "SHOW TABLE STATUS "',
' . ($db ? "FROM `$db`" : "")',
' . " LIKE \'$tbl\'";',
' MKDEBUG && _d($sql);',
' eval {',
' $engine = $dbh->selectrow_hashref($sql)->{engine};',
' };',
' MKDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);',
' MKDEBUG && _d($tbl, "uses engine", $engine);',
' $engine = lc $engine if $engine;',
@permit_engs
= _make_filter('unless', '$engine', $o->get('engines'), 1);
@reject_engs
= _make_filter('if', '$engine', $o->get('ignore-engines'), 1)
}
if ( @permit_tbls || @permit_qtbls || @reject_tbls || @tbls_regex
|| @reject_tbls_regex || @permit_engs || @reject_engs ) {
push @lines,
' if ( $tbl ) {',
(@permit_tbls ? @permit_tbls : ()),
(@reject_tbls ? @reject_tbls : ()),
(@tbls_regex ? @tbls_regex : ()),
(@reject_tbls_regex ? @reject_tbls_regex : ()),
(@permit_qtbls ? @permit_qtbls : ()),
(@reject_qtbls ? @reject_qtbls : ()),
(@get_eng ? @get_eng : ()),
(@permit_engs ? @permit_engs : ()),
(@reject_engs ? @reject_engs : ()),
' }';
}
}
push @lines,
' MKDEBUG && _d(\'Passes filters:\', $db, $tbl, $engine, $dbh);',
' return 1;', '}';
my $code = join("\n", @lines);
MKDEBUG && _d('filter sub:', $code);
my $filter_sub= eval $code
or die "Error compiling subroutine code:\n$code\n$EVAL_ERROR";
return $filter_sub;
}
sub set_filter {
my ( $self, $filter_sub ) = @_;
$self->{filter} = $filter_sub;
MKDEBUG && _d('Set filter sub');
return;
}
sub get_db_itr {
my ( $self, %args ) = @_;
my @required_args = qw(dbh);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($o, $q) = @args{@required_args};
my ($dbh) = @args{@required_args};
my %filters;
my @simple_filters = qw(
databases tables engines
ignore-databases ignore-tables ignore-engines);
FILTER:
foreach my $filter ( @simple_filters ) {
if ( $o->has($filter) ) {
my $objs = $o->get($filter);
next FILTER unless $objs && scalar keys %$objs;
my $is_table = $filter =~ m/table/ ? 1 : 0;
foreach my $obj ( keys %$objs ) {
die "Undefined value for --$filter" unless $obj;
$obj = lc $obj;
if ( $is_table ) {
my ($db, $tbl) = $q->split_unquote($obj);
$db ||= '*';
MKDEBUG && _d('Filter', $filter, 'value:', $db, $tbl);
$filters{$filter}->{$tbl} = $db;
}
else { # database
MKDEBUG && _d('Filter', $filter, 'value:', $obj);
$filters{$filter}->{$obj} = 1;
}
}
}
}
my @regex_filters = qw(
databases-regex tables-regex
ignore-databases-regex ignore-tables-regex);
REGEX_FILTER:
foreach my $filter ( @regex_filters ) {
if ( $o->has($filter) ) {
my $pat = $o->get($filter);
next REGEX_FILTER unless $pat;
$filters{$filter} = qr/$pat/;
MKDEBUG && _d('Filter', $filter, 'value:', $filters{$filter});
}
}
MKDEBUG && _d('Schema object filters:', Dumper(\%filters));
return \%filters;
}
sub next_schema_object {
my ( $self ) = @_;
my $schema_obj;
if ( $self->{file_itr} ) {
$schema_obj= $self->_iterate_files();
}
else { # dbh
$schema_obj= $self->_iterate_dbh();
}
if ( $schema_obj ) {
if ( $schema_obj->{ddl} && $self->{TableParser} ) {
$schema_obj->{tbl_struct}
= $self->{TableParser}->parse($schema_obj->{ddl});
}
delete $schema_obj->{ddl} unless $self->{keep_ddl};
if ( my $schema = $self->{Schema} ) {
$schema->add_schema_object($schema_obj);
}
}
MKDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
return $schema_obj;
}
sub _iterate_files {
my ( $self ) = @_;
if ( !$self->{fh} ) {
my ($fh, $file) = $self->{file_itr}->();
if ( !$fh ) {
MKDEBUG && _d('No more files to iterate');
return;
}
$self->{fh} = $fh;
$self->{file} = $file;
}
my $fh = $self->{fh};
MKDEBUG && _d('Getting next schema object from', $self->{file});
local $INPUT_RECORD_SEPARATOR = '';
CHUNK:
while (defined(my $chunk = <$fh>)) {
if ($chunk =~ m/Database: (\S+)/) {
my $db = $1; # XXX
$db =~ s/^`//; # strip leading `
$db =~ s/`$//; # and trailing `
if ( $self->database_is_allowed($db) ) {
$self->{db} = $db;
}
}
elsif ($self->{db} && $chunk =~ m/CREATE TABLE/) {
if ($chunk =~ m/DROP VIEW IF EXISTS/) {
MKDEBUG && _d('Table is a VIEW, skipping');
next CHUNK;
}
my ($tbl) = $chunk =~ m/$tbl_name/;
$tbl =~ s/^\s*`//;
$tbl =~ s/`\s*$//;
if ( $self->table_is_allowed($self->{db}, $tbl) ) {
my ($ddl) = $chunk =~ m/^(?:$open_comment)?(CREATE TABLE.+?;)$/ms;
if ( !$ddl ) {
warn "Failed to parse CREATE TABLE from\n" . $chunk;
next CHUNK;
}
$ddl =~ s/ \*\/;\Z/;/; # remove end of version comment
my ($engine) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/;
if ( !$engine || $self->engine_is_allowed($engine) ) {
return {
db => $self->{db},
tbl => $tbl,
ddl => $ddl,
};
}
}
}
} # CHUNK
MKDEBUG && _d('No more schema objects in', $self->{file});
close $self->{fh};
$self->{fh} = undef;
return $self->_iterate_files();
}
sub _iterate_dbh {
my ( $self ) = @_;
my $q = $self->{Quoter};
my $dbh = $self->{dbh};
MKDEBUG && _d('Getting next schema object from dbh', $dbh);
if ( !defined $self->{dbs} ) {
my $filter = $self->{filter};
my @dbs;
eval {
my $sql = 'SHOW DATABASES';
MKDEBUG && _d($sql);
my @dbs = grep { $self->database_is_allowed($_) }
@{$dbh->selectcol_arrayref($sql)};
@dbs = grep {
my $ok = $filter ? $filter->($dbh, $_, undef) : 1;
$ok = 0 if $_ =~ m/information_schema|performance_schema|lost\+found/;
$ok;
} @{ $dbh->selectcol_arrayref($sql) };
MKDEBUG && _d('Found', scalar @dbs, 'databases');
$self->{dbs} = \@dbs;
}
};
if ( !$self->{db} ) {
$self->{db} = shift @{$self->{dbs}};
MKDEBUG && _d('Next database:', $self->{db});
return unless $self->{db};
}
MKDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
my $iterator = sub {
return shift @dbs;
};
if ( !defined $self->{tbls} ) {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM ' . $q->quote($self->{db});
MKDEBUG && _d($sql);
my @tbls = map {
$_->[0]; # (tbl, type)
}
grep {
my ($tbl, $type) = @$_;
$self->table_is_allowed($self->{db}, $tbl)
&& (!$type || ($type ne 'VIEW'));
}
@{$dbh->selectall_arrayref($sql)};
MKDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
$self->{tbls} = \@tbls;
if (wantarray) {
return ($iterator, scalar @dbs);
}
else {
return $iterator;
}
}
while ( my $tbl = shift @{$self->{tbls}} ) {
my $engine;
if ( $self->{filters}->{'engines'}
|| $self->{filters}->{'ignore-engines'} ) {
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($self->{db})
. " LIKE \'$tbl\'";
sub get_tbl_itr {
my ( $self, %args ) = @_;
my @required_args = qw(dbh db);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $db, $views) = @args{@required_args, 'views'};
my $filter = $self->{filter};
my @tbls;
if ( $db ) {
eval {
my $sql = 'SHOW /*!50002 FULL*/ TABLES FROM '
. $self->{Quoter}->quote($db);
MKDEBUG && _d($sql);
$engine = $dbh->selectrow_hashref($sql)->{engine};
MKDEBUG && _d($tbl, 'uses', $engine, 'engine');
}
if ( !$engine || $self->engine_is_allowed($engine) ) {
my $ddl;
if ( my $du = $self->{MySQLDump} ) {
$ddl = $du->get_create_table($dbh, $q, $self->{db}, $tbl)->[1];
@tbls = map {
$_->[0]
}
return {
db => $self->{db},
tbl => $tbl,
ddl => $ddl,
};
}
grep {
my ($tbl, $type) = @$_;
my $ok = $filter ? $filter->($dbh, $db, $tbl) : 1;
if ( !$views ) {
$ok = 0 if ($type || '') eq 'VIEW';
}
$ok;
}
@{ $dbh->selectall_arrayref($sql) };
MKDEBUG && _d('Found', scalar @tbls, 'tables in', $db);
};
MKDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
}
else {
MKDEBUG && _d('No db given so no tables');
}
MKDEBUG && _d('No more tables in database', $self->{db});
$self->{db} = undef;
$self->{tbls} = undef;
my $iterator = sub {
return shift @tbls;
};
return $self->_iterate_dbh();
if ( wantarray ) {
return ($iterator, scalar @tbls);
}
else {
return $iterator;
}
}
sub database_is_allowed {
my ( $self, $db ) = @_;
die "I need a db argument" unless $db;
$db = lc $db;
my $filter = $self->{filters};
if ( $db =~ m/information_schema|performance_schema|lost\+found/ ) {
MKDEBUG && _d('Database', $db, 'is a system database, ignoring');
return 0;
sub _make_filter {
my ( $cond, $var_name, $objs, $lc ) = @_;
my @lines;
if ( scalar keys %$objs ) {
my $test = join(' || ',
map { "$var_name eq '" . ($lc ? lc $_ : $_) ."'" } keys %$objs);
push @lines, " return 0 $cond $var_name && ($test);",
}
if ( $self->{filters}->{'ignore-databases'}->{$db} ) {
MKDEBUG && _d('Database', $db, 'is in --ignore-databases list');
return 0;
}
if ( $filter->{'ignore-databases-regex'}
&& $db =~ $filter->{'ignore-databases-regex'} ) {
MKDEBUG && _d('Database', $db, 'matches --ignore-databases-regex');
return 0;
}
if ( $filter->{'databases'}
&& !$filter->{'databases'}->{$db} ) {
MKDEBUG && _d('Database', $db, 'is not in --databases list, ignoring');
return 0;
}
if ( $filter->{'databases-regex'}
&& $db !~ $filter->{'databases-regex'} ) {
MKDEBUG && _d('Database', $db, 'does not match --databases-regex, ignoring');
return 0;
}
return 1;
}
sub table_is_allowed {
my ( $self, $db, $tbl ) = @_;
die "I need a db argument" unless $db;
die "I need a tbl argument" unless $tbl;
$db = lc $db;
$tbl = lc $tbl;
my $filter = $self->{filters};
if ( $filter->{'ignore-tables'}->{$tbl}
&& ($filter->{'ignore-tables'}->{$tbl} eq '*'
|| $filter->{'ignore-tables'}->{$tbl} eq $db) ) {
MKDEBUG && _d('Table', $tbl, 'is in --ignore-tables list');
return 0;
}
if ( $filter->{'ignore-tables-regex'}
&& $tbl =~ $filter->{'ignore-tables-regex'} ) {
MKDEBUG && _d('Table', $tbl, 'matches --ignore-tables-regex');
return 0;
}
if ( $filter->{'tables'}
&& !$filter->{'tables'}->{$tbl} ) {
MKDEBUG && _d('Table', $tbl, 'is not in --tables list, ignoring');
return 0;
}
if ( $filter->{'tables-regex'}
&& $tbl !~ $filter->{'tables-regex'} ) {
MKDEBUG && _d('Table', $tbl, 'does not match --tables-regex, ignoring');
return 0;
}
if ( $filter->{'tables'}
&& $filter->{'tables'}->{$tbl}
&& $filter->{'tables'}->{$tbl} ne '*'
&& $filter->{'tables'}->{$tbl} ne $db ) {
MKDEBUG && _d('Table', $tbl, 'is only allowed in database',
$filter->{'tables'}->{$tbl});
return 0;
}
return 1;
}
sub engine_is_allowed {
my ( $self, $engine ) = @_;
die "I need an engine argument" unless $engine;
$engine = lc $engine;
my $filter = $self->{filters};
if ( $filter->{'ignore-engines'}->{$engine} ) {
MKDEBUG && _d('Engine', $engine, 'is in --ignore-databases list');
return 0;
}
if ( $filter->{'engines'}
&& !$filter->{'engines'}->{$engine} ) {
MKDEBUG && _d('Engine', $engine, 'is not in --engines list, ignoring');
return 0;
}
return 1;
return @lines;
}
sub _d {
@@ -6968,7 +6884,7 @@ sub _d {
}
1;
}
# ###########################################################################
# End SchemaIterator package
# ###########################################################################
@@ -10055,7 +9971,7 @@ User for login if not current user.
=back
=head1 DOWNLOADING
Visit L<http://www.percona.com/software/> to download the latest release of
Percona Toolkit. Or, to get the latest release from the command line: