diff --git a/lib/NibbleIterator.pm b/lib/NibbleIterator.pm index 517a0e98..5b506df6 100644 --- a/lib/NibbleIterator.pm +++ b/lib/NibbleIterator.pm @@ -305,10 +305,9 @@ sub statements { sub boundaries { my ($self) = @_; return { - first_lower => $self->{first_lb}, lower => $self->{lb}, - next_lower => $self->{next_lb}, upper => $self->{ub}, + next_lower => $self->{next_lb}, last_upper => $self->{last_ub}, }; } @@ -439,8 +438,7 @@ sub _get_bounds { my ($self) = @_; return if $self->{one_nibble}; - $self->{first_lb} = $self->{dbh}->selectrow_arrayref($self->{first_lb_sql}); - $self->{next_lb} = $self->{first_lb}; + $self->{next_lb} = $self->{dbh}->selectrow_arrayref($self->{first_lb_sql}); MKDEBUG && _d('First lower boundary:', Dumper($self->{next_lb})); $self->{last_ub} = $self->{dbh}->selectrow_arrayref($self->{last_ub_sql}); diff --git a/lib/SchemaIterator.pm b/lib/SchemaIterator.pm index 2c95c2c7..3dff10d3 100644 --- a/lib/SchemaIterator.pm +++ b/lib/SchemaIterator.pm @@ -60,6 +60,7 @@ my $tbl_name = qr{ # Schema - object to initialize while iterating. # TableParser - object to parse CREATE TABLE for tbl_struct. # keep_ddl - Keep CREATE TABLE (default false) +# resume - Skip tables so first call to returns this "db.table". # # Returns: # SchemaIterator object @@ -75,8 +76,17 @@ 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} ) { + MKDEBUG && _d('Will resume from', $table); + my ($db, $tbl) = $args{Quoter}->split_unquote($table); + $resume{db} = $db; + $resume{tbl} = $tbl; + } + my $self = { %args, + resume => \%resume, filters => _make_filters(%args), }; @@ -166,7 +176,7 @@ sub _make_filters { return \%filters; } -# Sub: next_schema_object +# Sub: next # Return the next schema object or undef when no more schema objects. # Only filtered schema objects are returned. If iterating dump files # (i.e. the obj was created with a file_itr arg), then the returned @@ -186,7 +196,7 @@ sub _make_filters { # } # (end code) # The ddl is suitable for . -sub next_schema_object { +sub next { my ( $self ) = @_; my $schema_obj; @@ -242,7 +252,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; } } @@ -261,7 +272,8 @@ 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->table_is_allowed($self->{db}, $tbl) + && $self->_resume_from_table($tbl) ) { my ($ddl) = $chunk =~ m/^(?:$open_comment)?(CREATE TABLE.+?;)$/ms; if ( !$ddl ) { warn "Failed to parse CREATE TABLE from\n" . $chunk; @@ -308,7 +320,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}); MKDEBUG && _d('Next database:', $self->{db}); return unless $self->{db}; } @@ -330,6 +344,7 @@ sub _iterate_dbh { } while ( my $tbl = shift @{$self->{tbls}} ) { + next unless $self->_resume_from_table($tbl); my $engine; if ( $self->{filters}->{'engines'} || $self->{filters}->{'ignore-engines'} ) { @@ -489,6 +504,36 @@ sub engine_is_allowed { return 1; } +sub _resume_from_database { + my ($self, $db) = @_; + + # "Resume" from any db if we're not, in fact, resuming. + return 1 unless $self->{resume}->{db}; + + if ( $db eq $self->{resume}->{db} ) { + MKDEBUG && _d('At resume db', $db); + delete $self->{resume}->{db}; + return 1; + } + + return 0; +} + +sub _resume_from_table { + my ($self, $tbl) = @_; + + # "Resume" from any table if we're not, in fact, resuming. + return 1 unless $self->{resume}->{tbl}; + + if ( $tbl eq $self->{resume}->{tbl} ) { + MKDEBUG && _d('At resume table', $tbl); + delete $self->{resume}->{tbl}; + return 1; + } + + return 0; +} + sub _d { my ($package, undef, $line) = caller 0; @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } diff --git a/t/lib/SchemaIterator.t b/t/lib/SchemaIterator.t index ecfe37c7..ff5cf74c 100644 --- a/t/lib/SchemaIterator.t +++ b/t/lib/SchemaIterator.t @@ -9,7 +9,7 @@ BEGIN { use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); -use Test::More tests => 29; +use Test::More tests => 30; use SchemaIterator; use FileIterator; @@ -56,6 +56,7 @@ sub test_so { $si = new SchemaIterator( file_itr => $file_itr, keep_ddl => defined $args{keep_ddl} ? $args{keep_ddl} : 1, + resume => $args{resume}, OptionParser => $o, Quoter => $q, TableParser => $tp, @@ -65,6 +66,7 @@ sub test_so { $si = new SchemaIterator( dbh => $dbh, keep_ddl => defined $args{keep_ddl} ? $args{keep_ddl} : 1, + resume => $args{resume}, OptionParser => $o, Quoter => $q, TableParser => $tp, @@ -77,7 +79,7 @@ sub test_so { my $res = ""; my @objs; - while ( my $obj = $si->next_schema_object() ) { + while ( my $obj = $si->next() ) { if ( $args{return_objs} ) { push @objs, $obj; } @@ -222,7 +224,7 @@ SKIP: { unless @{$dbh->selectcol_arrayref('SHOW DATABASES LIKE "sakila"')}; test_so( - filteres => [qw(-d sakila)], + filters => [qw(-d sakila)], result => "", # hack; uses unlike instead unlike => qr/ actor_info @@ -411,6 +413,21 @@ is( 'DDL deleted unless keep_ddl' ); +# ############################################################################ +# Resume +# ############################################################################ +SKIP: { + skip 'Sandbox master does not have the sakila database', 1 + unless @{$dbh->selectcol_arrayref('SHOW DATABASES LIKE "sakila"')}; + + test_so( + filters => [qw(-d sakila)], + result => "$out/resume-from-sakila-payment.txt", + resume => 'sakila.payment', + test_name => "Resume" + ); +}; + # ############################################################################# # Done. # ############################################################################# diff --git a/t/lib/samples/SchemaIterator/resume-from-sakila-payment.txt b/t/lib/samples/SchemaIterator/resume-from-sakila-payment.txt new file mode 100644 index 00000000..c6c7e307 --- /dev/null +++ b/t/lib/samples/SchemaIterator/resume-from-sakila-payment.txt @@ -0,0 +1,4 @@ +sakila.payment +sakila.rental +sakila.staff +sakila.store