mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-07 21:09:14 +00:00
Update SchemaIterator, TableParser, and NibbleIterator in tools that use them. All tools' tests still pass.
This commit is contained in:
@@ -199,19 +199,58 @@ sub new {
|
||||
return bless $self, $class;
|
||||
}
|
||||
|
||||
sub get_create_table {
|
||||
my ( $self, $dbh, $db, $tbl ) = @_;
|
||||
die "I need a dbh parameter" unless $dbh;
|
||||
die "I need a db parameter" unless $db;
|
||||
die "I need a tbl parameter" unless $tbl;
|
||||
my $q = $self->{Quoter};
|
||||
|
||||
my $new_sql_mode
|
||||
= '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
|
||||
. q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
|
||||
. '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
|
||||
. '@@SQL_QUOTE_SHOW_CREATE := 1 */';
|
||||
|
||||
my $old_sql_mode = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
|
||||
. '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
|
||||
|
||||
PTDEBUG && _d($new_sql_mode);
|
||||
eval { $dbh->do($new_sql_mode); };
|
||||
PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
|
||||
|
||||
my $use_sql = 'USE ' . $q->quote($db);
|
||||
PTDEBUG && _d($dbh, $use_sql);
|
||||
$dbh->do($use_sql);
|
||||
|
||||
my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl);
|
||||
PTDEBUG && _d($show_sql);
|
||||
my $href;
|
||||
eval { $href = $dbh->selectrow_hashref($show_sql); };
|
||||
if ( $EVAL_ERROR ) {
|
||||
PTDEBUG && _d($EVAL_ERROR);
|
||||
|
||||
PTDEBUG && _d($old_sql_mode);
|
||||
$dbh->do($old_sql_mode);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PTDEBUG && _d($old_sql_mode);
|
||||
$dbh->do($old_sql_mode);
|
||||
|
||||
my ($key) = grep { m/create (?:table|view)/i } keys %$href;
|
||||
if ( !$key ) {
|
||||
die "Error: no 'Create Table' or 'Create View' in result set from "
|
||||
. "$show_sql: " . Dumper($href);
|
||||
}
|
||||
|
||||
return $href->{$key};
|
||||
}
|
||||
|
||||
sub parse {
|
||||
my ( $self, $ddl, $opts ) = @_;
|
||||
return unless $ddl;
|
||||
if ( ref $ddl eq 'ARRAY' ) {
|
||||
if ( lc $ddl->[0] eq 'table' ) {
|
||||
$ddl = $ddl->[1];
|
||||
}
|
||||
else {
|
||||
return {
|
||||
engine => 'VIEW',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
|
||||
die "Cannot parse table definition; is ANSI quoting "
|
||||
@@ -518,41 +557,31 @@ sub remove_auto_increment {
|
||||
return $ddl;
|
||||
}
|
||||
|
||||
sub remove_secondary_indexes {
|
||||
my ( $self, $ddl ) = @_;
|
||||
my $sec_indexes_ddl;
|
||||
my $tbl_struct = $self->parse($ddl);
|
||||
|
||||
if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) {
|
||||
my $clustered_key = $tbl_struct->{clustered_key};
|
||||
$clustered_key ||= '';
|
||||
|
||||
my @sec_indexes = map {
|
||||
my $key_def = $_->{ddl};
|
||||
$key_def =~ s/([\(\)])/\\$1/g;
|
||||
$ddl =~ s/\s+$key_def//i;
|
||||
|
||||
my $key_ddl = "ADD $_->{ddl}";
|
||||
$key_ddl .= ',' unless $key_ddl =~ m/,$/;
|
||||
$key_ddl;
|
||||
}
|
||||
grep { $_->{name} ne $clustered_key }
|
||||
values %{$tbl_struct->{keys}};
|
||||
PTDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes));
|
||||
|
||||
if ( @sec_indexes ) {
|
||||
$sec_indexes_ddl = join(' ', @sec_indexes);
|
||||
$sec_indexes_ddl =~ s/,$//;
|
||||
}
|
||||
|
||||
$ddl =~ s/,(\n\) )/$1/s;
|
||||
sub get_table_status {
|
||||
my ( $self, $dbh, $db, $like ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db);
|
||||
my @params;
|
||||
if ( $like ) {
|
||||
$sql .= ' LIKE ?';
|
||||
push @params, $like;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Not removing secondary indexes from',
|
||||
$tbl_struct->{engine}, 'table');
|
||||
PTDEBUG && _d($sql, @params);
|
||||
my $sth = $dbh->prepare($sql);
|
||||
eval { $sth->execute(@params); };
|
||||
if ($EVAL_ERROR) {
|
||||
PTDEBUG && _d($EVAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
return $ddl, $sec_indexes_ddl, $tbl_struct;
|
||||
my @tables = @{$sth->fetchall_arrayref({})};
|
||||
@tables = map {
|
||||
my %tbl; # Make a copy with lowercased keys
|
||||
@tbl{ map { lc $_ } keys %$_ } = values %$_;
|
||||
$tbl{engine} ||= $tbl{type} || $tbl{comment};
|
||||
delete $tbl{type};
|
||||
\%tbl;
|
||||
} @tables;
|
||||
return @tables;
|
||||
}
|
||||
|
||||
sub _d {
|
||||
@@ -3195,7 +3224,7 @@ my $tbl_name = qr{
|
||||
|
||||
sub new {
|
||||
my ( $class, %args ) = @_;
|
||||
my @required_args = qw(OptionParser Quoter);
|
||||
my @required_args = qw(OptionParser TableParser Quoter);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
@@ -3204,8 +3233,19 @@ sub new {
|
||||
die "I need either a dbh or file_itr argument"
|
||||
if (!$dbh && !$file_itr) || ($dbh && $file_itr);
|
||||
|
||||
my %resume;
|
||||
if ( my $table = $args{resume} ) {
|
||||
PTDEBUG && _d('Will resume from or after', $table);
|
||||
my ($db, $tbl) = $args{Quoter}->split_unquote($table);
|
||||
die "Resume table must be database-qualified: $table"
|
||||
unless $db && $tbl;
|
||||
$resume{db} = $db;
|
||||
$resume{tbl} = $tbl;
|
||||
}
|
||||
|
||||
my $self = {
|
||||
%args,
|
||||
resume => \%resume,
|
||||
filters => _make_filters(%args),
|
||||
};
|
||||
|
||||
@@ -3266,9 +3306,19 @@ sub _make_filters {
|
||||
return \%filters;
|
||||
}
|
||||
|
||||
sub next_schema_object {
|
||||
sub next {
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{initialized} ) {
|
||||
$self->{initialized} = 1;
|
||||
if ( $self->{resume}->{tbl}
|
||||
&& !$self->table_is_allowed(@{$self->{resume}}{qw(db tbl)}) ) {
|
||||
PTDEBUG && _d('Will resume after',
|
||||
join('.', @{$self->{resume}}{qw(db tbl)}));
|
||||
$self->{resume}->{after} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $schema_obj;
|
||||
if ( $self->{file_itr} ) {
|
||||
$schema_obj= $self->_iterate_files();
|
||||
@@ -3278,24 +3328,18 @@ sub next_schema_object {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
PTDEBUG && _d('Next schema object:',
|
||||
$schema_obj->{db}, $schema_obj->{tbl});
|
||||
}
|
||||
|
||||
PTDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
|
||||
return $schema_obj;
|
||||
}
|
||||
|
||||
sub _iterate_files {
|
||||
my ( $self ) = @_;
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{fh} ) {
|
||||
my ($fh, $file) = $self->{file_itr}->();
|
||||
@@ -3316,7 +3360,8 @@ sub _iterate_files {
|
||||
my $db = $1; # XXX
|
||||
$db =~ s/^`//; # strip leading `
|
||||
$db =~ s/`$//; # and trailing `
|
||||
if ( $self->database_is_allowed($db) ) {
|
||||
if ( $self->database_is_allowed($db)
|
||||
&& $self->_resume_from_database($db) ) {
|
||||
$self->{db} = $db;
|
||||
}
|
||||
}
|
||||
@@ -3329,21 +3374,22 @@ sub _iterate_files {
|
||||
my ($tbl) = $chunk =~ m/$tbl_name/;
|
||||
$tbl =~ s/^\s*`//;
|
||||
$tbl =~ s/`\s*$//;
|
||||
if ( $self->table_is_allowed($self->{db}, $tbl) ) {
|
||||
if ( $self->_resume_from_table($tbl)
|
||||
&& $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) ) {
|
||||
my $tbl_struct = $self->{TableParser}->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $self->{Quoter}->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3360,6 +3406,7 @@ sub _iterate_files {
|
||||
sub _iterate_dbh {
|
||||
my ( $self ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $tp = $self->{TableParser};
|
||||
my $dbh = $self->{dbh};
|
||||
PTDEBUG && _d('Getting next schema object from dbh', $dbh);
|
||||
|
||||
@@ -3373,7 +3420,9 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
if ( !$self->{db} ) {
|
||||
$self->{db} = shift @{$self->{dbs}};
|
||||
do {
|
||||
$self->{db} = shift @{$self->{dbs}};
|
||||
} until $self->_resume_from_database($self->{db});
|
||||
PTDEBUG && _d('Next database:', $self->{db});
|
||||
return unless $self->{db};
|
||||
}
|
||||
@@ -3386,8 +3435,9 @@ sub _iterate_dbh {
|
||||
}
|
||||
grep {
|
||||
my ($tbl, $type) = @$_;
|
||||
$self->table_is_allowed($self->{db}, $tbl)
|
||||
&& (!$type || ($type ne 'VIEW'));
|
||||
(!$type || ($type ne 'VIEW'))
|
||||
&& $self->_resume_from_table($tbl)
|
||||
&& $self->table_is_allowed($self->{db}, $tbl);
|
||||
}
|
||||
@{$dbh->selectall_arrayref($sql)};
|
||||
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
|
||||
@@ -3395,27 +3445,15 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
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\'";
|
||||
PTDEBUG && _d($sql);
|
||||
$engine = $dbh->selectrow_hashref($sql)->{engine};
|
||||
PTDEBUG && _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];
|
||||
}
|
||||
|
||||
my $ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
my $tbl_struct = $tp->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3476,6 +3514,10 @@ sub table_is_allowed {
|
||||
|
||||
my $filter = $self->{filters};
|
||||
|
||||
if ( $db eq 'mysql' && ($tbl eq 'general_log' || $tbl eq 'slow_log') ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( $filter->{'ignore-tables'}->{$tbl}
|
||||
&& ($filter->{'ignore-tables'}->{$tbl} eq '*'
|
||||
|| $filter->{'ignore-tables'}->{$tbl} eq $db) ) {
|
||||
@@ -3515,7 +3557,11 @@ sub table_is_allowed {
|
||||
|
||||
sub engine_is_allowed {
|
||||
my ( $self, $engine ) = @_;
|
||||
die "I need an engine argument" unless $engine;
|
||||
|
||||
if ( !$engine ) {
|
||||
PTDEBUG && _d('No engine specified; allowing the table');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$engine = lc $engine;
|
||||
|
||||
@@ -3535,6 +3581,40 @@ sub engine_is_allowed {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _resume_from_database {
|
||||
my ($self, $db) = @_;
|
||||
|
||||
return 1 unless $self->{resume}->{db};
|
||||
|
||||
if ( $db eq $self->{resume}->{db} ) {
|
||||
PTDEBUG && _d('At resume db', $db);
|
||||
delete $self->{resume}->{db};
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _resume_from_table {
|
||||
my ($self, $tbl) = @_;
|
||||
|
||||
return 1 unless $self->{resume}->{tbl};
|
||||
|
||||
if ( $tbl eq $self->{resume}->{tbl} ) {
|
||||
if ( !$self->{resume}->{after} ) {
|
||||
PTDEBUG && _d('Resuming from table', $tbl);
|
||||
delete $self->{resume}->{tbl};
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Resuming after table', $tbl);
|
||||
delete $self->{resume}->{tbl};
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _d {
|
||||
my ($package, undef, $line) = caller 0;
|
||||
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
||||
@@ -3644,11 +3724,10 @@ sub main {
|
||||
MySQLDump => $du,
|
||||
TableParser => $tp,
|
||||
Schema => $schema,
|
||||
keep_ddl => 1,
|
||||
);
|
||||
TABLE:
|
||||
while ( my $tbl = $schema_itr->next_schema_object() ) {
|
||||
$tbl->{engine} = $tp->get_engine($tbl->{ddl});
|
||||
while ( my $tbl = $schema_itr->next() ) {
|
||||
$tbl->{engine} = $tbl->{tbl_struct}->{engine};
|
||||
|
||||
my ($keys, $clustered_key, $fks);
|
||||
if ( $get_keys ) {
|
||||
|
@@ -2669,19 +2669,58 @@ sub new {
|
||||
return bless $self, $class;
|
||||
}
|
||||
|
||||
sub get_create_table {
|
||||
my ( $self, $dbh, $db, $tbl ) = @_;
|
||||
die "I need a dbh parameter" unless $dbh;
|
||||
die "I need a db parameter" unless $db;
|
||||
die "I need a tbl parameter" unless $tbl;
|
||||
my $q = $self->{Quoter};
|
||||
|
||||
my $new_sql_mode
|
||||
= '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
|
||||
. q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
|
||||
. '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
|
||||
. '@@SQL_QUOTE_SHOW_CREATE := 1 */';
|
||||
|
||||
my $old_sql_mode = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
|
||||
. '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
|
||||
|
||||
PTDEBUG && _d($new_sql_mode);
|
||||
eval { $dbh->do($new_sql_mode); };
|
||||
PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
|
||||
|
||||
my $use_sql = 'USE ' . $q->quote($db);
|
||||
PTDEBUG && _d($dbh, $use_sql);
|
||||
$dbh->do($use_sql);
|
||||
|
||||
my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl);
|
||||
PTDEBUG && _d($show_sql);
|
||||
my $href;
|
||||
eval { $href = $dbh->selectrow_hashref($show_sql); };
|
||||
if ( $EVAL_ERROR ) {
|
||||
PTDEBUG && _d($EVAL_ERROR);
|
||||
|
||||
PTDEBUG && _d($old_sql_mode);
|
||||
$dbh->do($old_sql_mode);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PTDEBUG && _d($old_sql_mode);
|
||||
$dbh->do($old_sql_mode);
|
||||
|
||||
my ($key) = grep { m/create (?:table|view)/i } keys %$href;
|
||||
if ( !$key ) {
|
||||
die "Error: no 'Create Table' or 'Create View' in result set from "
|
||||
. "$show_sql: " . Dumper($href);
|
||||
}
|
||||
|
||||
return $href->{$key};
|
||||
}
|
||||
|
||||
sub parse {
|
||||
my ( $self, $ddl, $opts ) = @_;
|
||||
return unless $ddl;
|
||||
if ( ref $ddl eq 'ARRAY' ) {
|
||||
if ( lc $ddl->[0] eq 'table' ) {
|
||||
$ddl = $ddl->[1];
|
||||
}
|
||||
else {
|
||||
return {
|
||||
engine => 'VIEW',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
|
||||
die "Cannot parse table definition; is ANSI quoting "
|
||||
@@ -2988,41 +3027,31 @@ sub remove_auto_increment {
|
||||
return $ddl;
|
||||
}
|
||||
|
||||
sub remove_secondary_indexes {
|
||||
my ( $self, $ddl ) = @_;
|
||||
my $sec_indexes_ddl;
|
||||
my $tbl_struct = $self->parse($ddl);
|
||||
|
||||
if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) {
|
||||
my $clustered_key = $tbl_struct->{clustered_key};
|
||||
$clustered_key ||= '';
|
||||
|
||||
my @sec_indexes = map {
|
||||
my $key_def = $_->{ddl};
|
||||
$key_def =~ s/([\(\)])/\\$1/g;
|
||||
$ddl =~ s/\s+$key_def//i;
|
||||
|
||||
my $key_ddl = "ADD $_->{ddl}";
|
||||
$key_ddl .= ',' unless $key_ddl =~ m/,$/;
|
||||
$key_ddl;
|
||||
}
|
||||
grep { $_->{name} ne $clustered_key }
|
||||
values %{$tbl_struct->{keys}};
|
||||
PTDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes));
|
||||
|
||||
if ( @sec_indexes ) {
|
||||
$sec_indexes_ddl = join(' ', @sec_indexes);
|
||||
$sec_indexes_ddl =~ s/,$//;
|
||||
}
|
||||
|
||||
$ddl =~ s/,(\n\) )/$1/s;
|
||||
sub get_table_status {
|
||||
my ( $self, $dbh, $db, $like ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db);
|
||||
my @params;
|
||||
if ( $like ) {
|
||||
$sql .= ' LIKE ?';
|
||||
push @params, $like;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Not removing secondary indexes from',
|
||||
$tbl_struct->{engine}, 'table');
|
||||
PTDEBUG && _d($sql, @params);
|
||||
my $sth = $dbh->prepare($sql);
|
||||
eval { $sth->execute(@params); };
|
||||
if ($EVAL_ERROR) {
|
||||
PTDEBUG && _d($EVAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
return $ddl, $sec_indexes_ddl, $tbl_struct;
|
||||
my @tables = @{$sth->fetchall_arrayref({})};
|
||||
@tables = map {
|
||||
my %tbl; # Make a copy with lowercased keys
|
||||
@tbl{ map { lc $_ } keys %$_ } = values %$_;
|
||||
$tbl{engine} ||= $tbl{type} || $tbl{comment};
|
||||
delete $tbl{type};
|
||||
\%tbl;
|
||||
} @tables;
|
||||
return @tables;
|
||||
}
|
||||
|
||||
sub _d {
|
||||
@@ -3912,7 +3941,7 @@ my $tbl_name = qr{
|
||||
|
||||
sub new {
|
||||
my ( $class, %args ) = @_;
|
||||
my @required_args = qw(OptionParser Quoter);
|
||||
my @required_args = qw(OptionParser TableParser Quoter);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
@@ -3921,8 +3950,19 @@ sub new {
|
||||
die "I need either a dbh or file_itr argument"
|
||||
if (!$dbh && !$file_itr) || ($dbh && $file_itr);
|
||||
|
||||
my %resume;
|
||||
if ( my $table = $args{resume} ) {
|
||||
PTDEBUG && _d('Will resume from or after', $table);
|
||||
my ($db, $tbl) = $args{Quoter}->split_unquote($table);
|
||||
die "Resume table must be database-qualified: $table"
|
||||
unless $db && $tbl;
|
||||
$resume{db} = $db;
|
||||
$resume{tbl} = $tbl;
|
||||
}
|
||||
|
||||
my $self = {
|
||||
%args,
|
||||
resume => \%resume,
|
||||
filters => _make_filters(%args),
|
||||
};
|
||||
|
||||
@@ -3983,9 +4023,19 @@ sub _make_filters {
|
||||
return \%filters;
|
||||
}
|
||||
|
||||
sub next_schema_object {
|
||||
sub next {
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{initialized} ) {
|
||||
$self->{initialized} = 1;
|
||||
if ( $self->{resume}->{tbl}
|
||||
&& !$self->table_is_allowed(@{$self->{resume}}{qw(db tbl)}) ) {
|
||||
PTDEBUG && _d('Will resume after',
|
||||
join('.', @{$self->{resume}}{qw(db tbl)}));
|
||||
$self->{resume}->{after} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $schema_obj;
|
||||
if ( $self->{file_itr} ) {
|
||||
$schema_obj= $self->_iterate_files();
|
||||
@@ -3995,24 +4045,18 @@ sub next_schema_object {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
PTDEBUG && _d('Next schema object:',
|
||||
$schema_obj->{db}, $schema_obj->{tbl});
|
||||
}
|
||||
|
||||
PTDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
|
||||
return $schema_obj;
|
||||
}
|
||||
|
||||
sub _iterate_files {
|
||||
my ( $self ) = @_;
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{fh} ) {
|
||||
my ($fh, $file) = $self->{file_itr}->();
|
||||
@@ -4033,7 +4077,8 @@ sub _iterate_files {
|
||||
my $db = $1; # XXX
|
||||
$db =~ s/^`//; # strip leading `
|
||||
$db =~ s/`$//; # and trailing `
|
||||
if ( $self->database_is_allowed($db) ) {
|
||||
if ( $self->database_is_allowed($db)
|
||||
&& $self->_resume_from_database($db) ) {
|
||||
$self->{db} = $db;
|
||||
}
|
||||
}
|
||||
@@ -4046,21 +4091,22 @@ sub _iterate_files {
|
||||
my ($tbl) = $chunk =~ m/$tbl_name/;
|
||||
$tbl =~ s/^\s*`//;
|
||||
$tbl =~ s/`\s*$//;
|
||||
if ( $self->table_is_allowed($self->{db}, $tbl) ) {
|
||||
if ( $self->_resume_from_table($tbl)
|
||||
&& $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) ) {
|
||||
my $tbl_struct = $self->{TableParser}->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $self->{Quoter}->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4077,6 +4123,7 @@ sub _iterate_files {
|
||||
sub _iterate_dbh {
|
||||
my ( $self ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $tp = $self->{TableParser};
|
||||
my $dbh = $self->{dbh};
|
||||
PTDEBUG && _d('Getting next schema object from dbh', $dbh);
|
||||
|
||||
@@ -4090,7 +4137,9 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
if ( !$self->{db} ) {
|
||||
$self->{db} = shift @{$self->{dbs}};
|
||||
do {
|
||||
$self->{db} = shift @{$self->{dbs}};
|
||||
} until $self->_resume_from_database($self->{db});
|
||||
PTDEBUG && _d('Next database:', $self->{db});
|
||||
return unless $self->{db};
|
||||
}
|
||||
@@ -4103,8 +4152,9 @@ sub _iterate_dbh {
|
||||
}
|
||||
grep {
|
||||
my ($tbl, $type) = @$_;
|
||||
$self->table_is_allowed($self->{db}, $tbl)
|
||||
&& (!$type || ($type ne 'VIEW'));
|
||||
(!$type || ($type ne 'VIEW'))
|
||||
&& $self->_resume_from_table($tbl)
|
||||
&& $self->table_is_allowed($self->{db}, $tbl);
|
||||
}
|
||||
@{$dbh->selectall_arrayref($sql)};
|
||||
PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
|
||||
@@ -4112,27 +4162,15 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
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\'";
|
||||
PTDEBUG && _d($sql);
|
||||
$engine = $dbh->selectrow_hashref($sql)->{engine};
|
||||
PTDEBUG && _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];
|
||||
}
|
||||
|
||||
my $ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
my $tbl_struct = $tp->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4193,6 +4231,10 @@ sub table_is_allowed {
|
||||
|
||||
my $filter = $self->{filters};
|
||||
|
||||
if ( $db eq 'mysql' && ($tbl eq 'general_log' || $tbl eq 'slow_log') ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( $filter->{'ignore-tables'}->{$tbl}
|
||||
&& ($filter->{'ignore-tables'}->{$tbl} eq '*'
|
||||
|| $filter->{'ignore-tables'}->{$tbl} eq $db) ) {
|
||||
@@ -4232,7 +4274,11 @@ sub table_is_allowed {
|
||||
|
||||
sub engine_is_allowed {
|
||||
my ( $self, $engine ) = @_;
|
||||
die "I need an engine argument" unless $engine;
|
||||
|
||||
if ( !$engine ) {
|
||||
PTDEBUG && _d('No engine specified; allowing the table');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$engine = lc $engine;
|
||||
|
||||
@@ -4252,6 +4298,40 @@ sub engine_is_allowed {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _resume_from_database {
|
||||
my ($self, $db) = @_;
|
||||
|
||||
return 1 unless $self->{resume}->{db};
|
||||
|
||||
if ( $db eq $self->{resume}->{db} ) {
|
||||
PTDEBUG && _d('At resume db', $db);
|
||||
delete $self->{resume}->{db};
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _resume_from_table {
|
||||
my ($self, $tbl) = @_;
|
||||
|
||||
return 1 unless $self->{resume}->{tbl};
|
||||
|
||||
if ( $tbl eq $self->{resume}->{tbl} ) {
|
||||
if ( !$self->{resume}->{after} ) {
|
||||
PTDEBUG && _d('Resuming from table', $tbl);
|
||||
delete $self->{resume}->{tbl};
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('Resuming after table', $tbl);
|
||||
delete $self->{resume}->{tbl};
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub _d {
|
||||
my ($package, undef, $line) = caller 0;
|
||||
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
||||
@@ -5144,13 +5224,11 @@ sub main {
|
||||
dbh => $dbh,
|
||||
OptionParser => $o,
|
||||
Quoter => $q,
|
||||
MySQLDump => $du,
|
||||
TableParser => $tp,
|
||||
Schema => $schema,
|
||||
keep_ddl => 1,
|
||||
);
|
||||
TALBE:
|
||||
while ( my $tbl = $schema_itr->next_schema_object() ) {
|
||||
while ( my $tbl = $schema_itr->next() ) {
|
||||
eval {
|
||||
my ($indexes) = $tp->get_keys($tbl->{ddl}, {version => $version});
|
||||
$iu->add_indexes(%$tbl, indexes=>$indexes);
|
||||
|
@@ -3941,22 +3941,15 @@ sub _get_index_cardinality {
|
||||
|
||||
sub get_row_estimate {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl OptionParser TableParser Quoter);
|
||||
my ($cxn, $tbl, $o, $tp, $q) = @args{@required_args};
|
||||
my @required_args = qw(Cxn tbl);
|
||||
my ($cxn, $tbl) = @args{@required_args};
|
||||
|
||||
if ( $args{where} ) {
|
||||
PTDEBUG && _d('WHERE clause, using explain plan for row estimate');
|
||||
my $table = $q->quote(@{$tbl}{qw(db tbl)});
|
||||
my $sql = "EXPLAIN SELECT * FROM $table WHERE $args{where}";
|
||||
PTDEBUG && _d($sql);
|
||||
my $expl = $cxn->dbh()->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($expl));
|
||||
return ($expl->{rows} || 0), $expl->{key};
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('No WHERE clause, using table status for row estimate');
|
||||
return $tbl->{tbl_status}->{rows} || 0;
|
||||
}
|
||||
my $sql = "EXPLAIN SELECT * FROM $tbl->{name} "
|
||||
. "WHERE " . ($args{where} || '1=1');
|
||||
PTDEBUG && _d($sql);
|
||||
my $expl = $cxn->dbh()->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($expl));
|
||||
return ($expl->{rows} || 0), $expl->{key};
|
||||
}
|
||||
|
||||
sub _prepare_sths {
|
||||
@@ -4543,7 +4536,7 @@ my $tbl_name = qr{
|
||||
|
||||
sub new {
|
||||
my ( $class, %args ) = @_;
|
||||
my @required_args = qw(OptionParser Quoter);
|
||||
my @required_args = qw(OptionParser TableParser Quoter);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
@@ -4647,25 +4640,18 @@ sub next {
|
||||
}
|
||||
|
||||
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};
|
||||
delete $schema_obj->{tbl_status} unless $self->{keep_tbl_status};
|
||||
|
||||
if ( my $schema = $self->{Schema} ) {
|
||||
$schema->add_schema_object($schema_obj);
|
||||
}
|
||||
PTDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
|
||||
PTDEBUG && _d('Next schema object:',
|
||||
$schema_obj->{db}, $schema_obj->{tbl});
|
||||
}
|
||||
|
||||
return $schema_obj;
|
||||
}
|
||||
|
||||
sub _iterate_files {
|
||||
my ( $self ) = @_;
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{fh} ) {
|
||||
my ($fh, $file) = $self->{file_itr}->();
|
||||
@@ -4708,14 +4694,14 @@ sub _iterate_files {
|
||||
next CHUNK;
|
||||
}
|
||||
$ddl =~ s/ \*\/;\Z/;/; # remove end of version comment
|
||||
|
||||
my ($engine) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/;
|
||||
|
||||
if ( !$engine || $self->engine_is_allowed($engine) ) {
|
||||
my $tbl_struct = $self->{TableParser}->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $self->{Quoter}->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4732,6 +4718,7 @@ sub _iterate_files {
|
||||
sub _iterate_dbh {
|
||||
my ( $self ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $tp = $self->{TableParser};
|
||||
my $dbh = $self->{dbh};
|
||||
PTDEBUG && _d('Getting next schema object from dbh', $dbh);
|
||||
|
||||
@@ -4770,30 +4757,15 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
while ( my $tbl = shift @{$self->{tbls}} ) {
|
||||
my $tbl_status;
|
||||
if ( $self->{filters}->{'engines'}
|
||||
|| $self->{filters}->{'ignore-engines'}
|
||||
|| $self->{keep_tbl_status} )
|
||||
{
|
||||
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($self->{db})
|
||||
. " LIKE \'$tbl\'";
|
||||
PTDEBUG && _d($sql);
|
||||
$tbl_status = $dbh->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($tbl_status));
|
||||
}
|
||||
|
||||
if ( !$tbl_status
|
||||
|| $self->engine_is_allowed($tbl_status->{engine}) ) {
|
||||
my $ddl;
|
||||
if ( my $tp = $self->{TableParser} ) {
|
||||
$ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
}
|
||||
|
||||
my $ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
my $tbl_struct = $tp->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_status => $tbl_status,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4897,7 +4869,11 @@ sub table_is_allowed {
|
||||
|
||||
sub engine_is_allowed {
|
||||
my ( $self, $engine ) = @_;
|
||||
die "I need an engine argument" unless $engine;
|
||||
|
||||
if ( !$engine ) {
|
||||
PTDEBUG && _d('No engine specified; allowing the table');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$engine = lc $engine;
|
||||
|
||||
@@ -6253,13 +6229,12 @@ sub main {
|
||||
}
|
||||
|
||||
my $schema_iter = new SchemaIterator(
|
||||
dbh => $master_dbh,
|
||||
resume => $last_chunk ? $q->quote(@{$last_chunk}{qw(db tbl)})
|
||||
: "",
|
||||
keep_tbl_status => 1,
|
||||
OptionParser => $o,
|
||||
TableParser => $tp,
|
||||
Quoter => $q,
|
||||
dbh => $master_dbh,
|
||||
resume => $last_chunk ? $q->quote(@{$last_chunk}{qw(db tbl)})
|
||||
: "",
|
||||
OptionParser => $o,
|
||||
TableParser => $tp,
|
||||
Quoter => $q,
|
||||
);
|
||||
|
||||
if ( $last_chunk &&
|
||||
@@ -6334,13 +6309,13 @@ sub main {
|
||||
my $chunk_size_limit = $o->get('chunk-size-limit');
|
||||
my @too_large;
|
||||
foreach my $slave ( @$slaves ) {
|
||||
# get_row_estimate() returns (row_est, index), but
|
||||
# we only need the row_est. Maybe in the future we'll
|
||||
# care what index MySQL will use on a slave.
|
||||
my ($n_rows) = NibbleIterator::get_row_estimate(
|
||||
Cxn => $slave,
|
||||
tbl => $tbl,
|
||||
where => $o->get('where') || "1=1",
|
||||
OptionParser => $o,
|
||||
TableParser => $tp,
|
||||
Quoter => $q,
|
||||
Cxn => $slave,
|
||||
tbl => $tbl,
|
||||
where => $o->get('where'),
|
||||
);
|
||||
PTDEBUG && _d('Table on', $slave->name(),
|
||||
'has', $n_rows, 'rows');
|
||||
|
@@ -6782,7 +6782,7 @@ my $tbl_name = qr{
|
||||
|
||||
sub new {
|
||||
my ( $class, %args ) = @_;
|
||||
my @required_args = qw(OptionParser Quoter);
|
||||
my @required_args = qw(OptionParser TableParser Quoter);
|
||||
foreach my $arg ( @required_args ) {
|
||||
die "I need a $arg argument" unless $args{$arg};
|
||||
}
|
||||
@@ -6801,15 +6801,10 @@ sub new {
|
||||
$resume{tbl} = $tbl;
|
||||
}
|
||||
|
||||
my $engine_key
|
||||
= $dbh && ($dbh->{FetchHashKeyName} || '') eq 'NAME_lc' ? 'engine'
|
||||
: 'Engine';
|
||||
|
||||
my $self = {
|
||||
%args,
|
||||
resume => \%resume,
|
||||
filters => _make_filters(%args),
|
||||
engine_key => $engine_key,
|
||||
resume => \%resume,
|
||||
filters => _make_filters(%args),
|
||||
};
|
||||
|
||||
return bless $self, $class;
|
||||
@@ -6891,25 +6886,18 @@ sub next {
|
||||
}
|
||||
|
||||
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};
|
||||
delete $schema_obj->{tbl_status} unless $self->{keep_tbl_status};
|
||||
|
||||
if ( my $schema = $self->{Schema} ) {
|
||||
$schema->add_schema_object($schema_obj);
|
||||
}
|
||||
PTDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
|
||||
PTDEBUG && _d('Next schema object:',
|
||||
$schema_obj->{db}, $schema_obj->{tbl});
|
||||
}
|
||||
|
||||
return $schema_obj;
|
||||
}
|
||||
|
||||
sub _iterate_files {
|
||||
my ( $self ) = @_;
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( !$self->{fh} ) {
|
||||
my ($fh, $file) = $self->{file_itr}->();
|
||||
@@ -6952,14 +6940,14 @@ sub _iterate_files {
|
||||
next CHUNK;
|
||||
}
|
||||
$ddl =~ s/ \*\/;\Z/;/; # remove end of version comment
|
||||
|
||||
my ($engine) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/;
|
||||
|
||||
if ( !$engine || $self->engine_is_allowed($engine) ) {
|
||||
my $tbl_struct = $self->{TableParser}->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
ddl => $ddl,
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $self->{Quoter}->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6976,6 +6964,7 @@ sub _iterate_files {
|
||||
sub _iterate_dbh {
|
||||
my ( $self ) = @_;
|
||||
my $q = $self->{Quoter};
|
||||
my $tp = $self->{TableParser};
|
||||
my $dbh = $self->{dbh};
|
||||
PTDEBUG && _d('Getting next schema object from dbh', $dbh);
|
||||
|
||||
@@ -7014,30 +7003,15 @@ sub _iterate_dbh {
|
||||
}
|
||||
|
||||
while ( my $tbl = shift @{$self->{tbls}} ) {
|
||||
my $tbl_status;
|
||||
if ( $self->{filters}->{'engines'}
|
||||
|| $self->{filters}->{'ignore-engines'}
|
||||
|| $self->{keep_tbl_status} )
|
||||
{
|
||||
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($self->{db})
|
||||
. " LIKE \'$tbl\'";
|
||||
PTDEBUG && _d($sql);
|
||||
$tbl_status = $dbh->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($tbl_status));
|
||||
}
|
||||
|
||||
if ( !$tbl_status
|
||||
|| $self->engine_is_allowed($tbl_status->{$self->{engine_key}}) ) {
|
||||
my $ddl;
|
||||
if ( my $tp = $self->{TableParser} ) {
|
||||
$ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
}
|
||||
|
||||
my $ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
|
||||
my $tbl_struct = $tp->parse($ddl);
|
||||
if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
|
||||
return {
|
||||
db => $self->{db},
|
||||
tbl => $tbl,
|
||||
name => $q->quote($self->{db}, $tbl),
|
||||
ddl => $ddl,
|
||||
tbl_status => $tbl_status,
|
||||
tbl_struct => $tbl_struct,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7141,7 +7115,11 @@ sub table_is_allowed {
|
||||
|
||||
sub engine_is_allowed {
|
||||
my ( $self, $engine ) = @_;
|
||||
die "I need an engine argument" unless $engine;
|
||||
|
||||
if ( !$engine ) {
|
||||
PTDEBUG && _d('No engine specified; allowing the table');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$engine = lc $engine;
|
||||
|
||||
@@ -8188,12 +8166,10 @@ sub sync_all {
|
||||
};
|
||||
|
||||
my $schema_iter = new SchemaIterator(
|
||||
dbh => $src->{dbh},
|
||||
keep_tbl_status => 1,
|
||||
keep_ddl => 1,
|
||||
OptionParser => $o,
|
||||
TableParser => $args{TableParser},
|
||||
Quoter => $args{Quoter},
|
||||
dbh => $src->{dbh},
|
||||
OptionParser => $o,
|
||||
TableParser => $args{TableParser},
|
||||
Quoter => $args{Quoter},
|
||||
);
|
||||
|
||||
# Make a list of all dbs.tbls on the source. It's more efficient this
|
||||
|
@@ -511,22 +511,15 @@ sub _get_index_cardinality {
|
||||
|
||||
sub get_row_estimate {
|
||||
my (%args) = @_;
|
||||
my @required_args = qw(Cxn tbl OptionParser TableParser Quoter);
|
||||
my ($cxn, $tbl, $o, $tp, $q) = @args{@required_args};
|
||||
my @required_args = qw(Cxn tbl);
|
||||
my ($cxn, $tbl) = @args{@required_args};
|
||||
|
||||
if ( $args{where} ) {
|
||||
PTDEBUG && _d('WHERE clause, using explain plan for row estimate');
|
||||
my $table = $q->quote(@{$tbl}{qw(db tbl)});
|
||||
my $sql = "EXPLAIN SELECT * FROM $table WHERE $args{where}";
|
||||
PTDEBUG && _d($sql);
|
||||
my $expl = $cxn->dbh()->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($expl));
|
||||
return ($expl->{rows} || 0), $expl->{key};
|
||||
}
|
||||
else {
|
||||
PTDEBUG && _d('No WHERE clause, using table status for row estimate');
|
||||
return $tbl->{tbl_status}->{rows} || 0;
|
||||
}
|
||||
my $sql = "EXPLAIN SELECT * FROM $tbl->{name} "
|
||||
. "WHERE " . ($args{where} || '1=1');
|
||||
PTDEBUG && _d($sql);
|
||||
my $expl = $cxn->dbh()->selectrow_hashref($sql);
|
||||
PTDEBUG && _d(Dumper($expl));
|
||||
return ($expl->{rows} || 0), $expl->{key};
|
||||
}
|
||||
|
||||
sub _prepare_sths {
|
||||
|
Reference in New Issue
Block a user