Change --update-foreign-keys-method to --alter-foreign-keys-method and make it required if there are child tables. Add 'auto' and 'none' (this one yet implemented) as methods. Fix drop_swap when it's auto-chosen. Test that the expected method is used. Exit 1 instead of 0 if user didn't specify required options.

This commit is contained in:
Daniel Nichter
2012-03-29 11:30:20 -06:00
parent d677436f73
commit 044b16f230
3 changed files with 266 additions and 167 deletions

View File

@@ -4936,10 +4936,10 @@ sub main {
$tbl = $dsn->{t};
}
my $update_fk_method = $o->get('update-foreign-keys-method') || '';
if ( $update_fk_method eq 'drop_swap' ) {
my $alter_fk_method = $o->get('alter-foreign-keys-method') || '';
if ( $alter_fk_method =~ m/^(?:drop_swap|none)/ ) {
$o->set('swap-tables', 0);
$o->set('drop-old-table', 0),
$o->set('drop-old-table', 0);
}
# Explicit --chunk-size disable auto chunk sizing.
@@ -4964,11 +4964,13 @@ sub main {
# See the "pod-based-option-value-validation" spec for how this may
# be automagically validated.
if ( $update_fk_method
&& $update_fk_method ne 'rebuild_constraints'
&& $update_fk_method ne 'drop_swap' )
if ( $alter_fk_method
&& $alter_fk_method ne 'auto'
&& $alter_fk_method ne 'rebuild_constraints'
&& $alter_fk_method ne 'drop_swap'
&& $alter_fk_method ne 'none' )
{
$o->save_error("Invalid --update-foreign-keys-method value: $update_fk_method");
$o->save_error("Invalid --alter-foreign-keys-method value: $alter_fk_method");
}
}
@@ -5233,18 +5235,37 @@ sub main {
Cxn => $cxn,
Quoter => $q,
);
if ( $o->got('update-foreign-keys-method') && ! @$child_tables ) {
warn "No foreign keys reference the table; ignoring --update-foreign-keys-method\n";
if ( !$child_tables ) {
if ( $alter_fk_method ) {
warn "No foreign keys reference the table; ignoring "
. "--alter-foreign-keys-method.\n";
}
# No child tables and --alter-fk-method wasn't specified,
# so nothing to do.
}
else {
print "Child tables:\n";
print " $_->{name}\n" for @$child_tables;
foreach my $child_table ( @$child_tables ) {
printf " %s (approx. %s rows)\n",
$child_table->{name},
$child_table->{row_est} || '?';
}
# Let the user know how we're going to update the child table fk refs.
print "Will "
. ($update_fk_method ? "use the $update_fk_method"
: "automatically determine the")
. " method to update child table foreign keys.\n";
if ( $alter_fk_method ) {
# Let the user know how we're going to update the child table fk refs.
my $choice
= $alter_fk_method eq 'none' ? "not"
: $alter_fk_method eq 'auto' ? "automatically choose the method to"
: "use the $alter_fk_method method to";
print "Will $choice update child table foreign keys.\n";
}
else {
print "Exiting without altering $orig_tbl->{name} because there "
. "are child tables but --alter-foreign-keys-method was not "
. "specified. Please read the tool's documentation carefully "
. "and specify --alter-foreign-keys-method.\n";
return 1;
}
}
# ########################################################################
@@ -5266,7 +5287,7 @@ sub main {
print "Exiting without altering $orig_tbl->{name} because neither "
. "--dry-run nor --execute was specified. Please read the tool's "
. "documentation carefully before using this tool.\n";
return $exit_status;
return 1;
}
# ########################################################################
@@ -5788,6 +5809,37 @@ sub main {
}
$orig_tbl->{copied} = 1; # flag for cleanup tasks
# XXX Auto-choose the alter fk method BEFORE swapping/renaming tables
# else everything will break because if drop_swap is chosen, then we
# most NOT rename tables or drop the old table.
if ( $alter_fk_method eq 'auto' ) {
# If chunk time is set, then use the average rate of rows/s
# from copying the orig table to determine the max size of
# a child table that can be altered within one chunk time.
# The limit is a fudge factor. Chunk time won't be set if
# the user specified --chunk-size=N on the cmd line, in which
# case the max child table size is their specified chunk size
# times the fudge factor.
my $max_rows
= $o->get('dry-run') ? $o->get('chunk-size') * $limit
: $chunk_time ? $avg_rate * $chunk_time * $limit
: $o->get('chunk-size') * $limit;
PTDEBUG && _d('Max allowed child table size:', $max_rows);
$alter_fk_method = determine_alter_fk_method(
child_tables => $child_tables,
max_rows => $max_rows,
Cxn => $cxn,
OptionParser => $o,
);
if ( $alter_fk_method eq 'drop_swap' ) {
$o->set('swap-tables', 0);
$o->set('drop-old-table', 0);
}
}
# #####################################################################
# XXX
# Step 5: Rename tables: orig -> old, new -> orig
@@ -5823,27 +5875,12 @@ sub main {
# #####################################################################
if ( $child_tables ) {
eval {
if ( !$update_fk_method ) {
# If chunk time is set, then use the average rate of rows/s
# from copying the orig table to determine the max size of
# a child table that can be altered within one chunk time.
# The limit is a fudge factor. Chunk time won't be set if
# the user specified --chunk-size=N on the cmd line, in which
# case the max child table size is their specified chunk size
# times the fudge factor.
my $max_rows = $o->get('dry-run') ? $o->get('chunk-size') * $limit
: $chunk_time ? $avg_rate * $chunk_time * $limit
: $o->get('chunk-size') * $limit;
PTDEBUG && _d('Max allowed child table size:', $max_rows);
$update_fk_method = determine_update_fk_method(
child_tables => $child_tables,
max_rows => $max_rows,
Cxn => $cxn,
OptionParser => $o,
);
if ( $alter_fk_method eq 'none' ) {
print "Not updating child table foreign keys because "
. "--alter-foreign-keys-method=none. Child table foreign "
. "keys will be broken when the tool finishes.\n";
}
if ( ($update_fk_method || '') eq 'rebuild_constraints' ) {
elsif ( $alter_fk_method eq 'rebuild_constraints' ) {
rebuild_constraints(
orig_tbl => $orig_tbl,
old_tbl => $old_tbl,
@@ -5854,7 +5891,7 @@ sub main {
TableParser => $tp,
);
}
elsif ( ($update_fk_method || '') eq 'drop_swap' ) {
elsif ( $alter_fk_method eq 'drop_swap' ) {
drop_swap(
orig_tbl => $orig_tbl,
new_tbl => $new_tbl,
@@ -5862,6 +5899,10 @@ sub main {
OptionParser => $o,
);
}
else {
# This should "never" happen because we check this var earlier.
die "Invalid --alter-foreign-keys-method: $alter_fk_method\n";
}
};
if ( $EVAL_ERROR ) {
# TODO: improve error message and handling.
@@ -6106,25 +6147,37 @@ sub find_child_tables {
. "WHERE constraint_schema='$tbl->{db}' "
. "AND referenced_table_name='$tbl->{tbl}'";
PTDEBUG && _d($sql);
my $child_tables = $cxn->dbh()->selectall_arrayref($sql);
if ( !$child_tables || !@$child_tables ) {
my $rows = $cxn->dbh()->selectall_arrayref($sql);
if ( !$rows || !@$rows ) {
PTDEBUG && _d('No child tables found');
return;
}
my @child_tables = map {
my @child_tables;
foreach my $row ( @$rows ) {
my $tbl = {
db => $_->[0],
tbl => $_->[1],
name => $q->quote(@$_),
db => $row->[0],
tbl => $row->[1],
name => $q->quote(@$row),
};
$tbl;
} @$child_tables;
PTDEBUG && _d("Child tables:", @child_tables);
# Get row estimates for each child table so we can give the user
# some input on choosing an --alter-foreign-keys-method if they
# don't use "auto".
my ($n_rows) = NibbleIterator::get_row_estimate(
Cxn => $cxn,
tbl => $tbl,
);
$tbl->{row_est} = $n_rows;
push @child_tables, $tbl;
}
PTDEBUG && _d('Child tables:', Dumper(\@child_tables));
return \@child_tables;
}
sub determine_update_fk_method {
sub determine_alter_fk_method {
my ( %args ) = @_;
my @required_args = qw(child_tables max_rows Cxn OptionParser);
foreach my $arg ( @required_args ) {
@@ -6135,7 +6188,7 @@ sub determine_update_fk_method {
if ( $o->get('dry-run') ) {
print "Not determining the method to update child table foreign keys "
. "because this is a dry run.\n";
return;
return ''; # $alter_fk_method can't be undef
}
# The rebuild_constraints method is the default becuase it's safer
@@ -6160,7 +6213,7 @@ sub determine_update_fk_method {
}
}
return $method;
return $method || ''; # $alter_fk_method can't be undef
}
sub rebuild_constraints {
@@ -6226,10 +6279,10 @@ sub rebuild_constraints {
# constraint has the same name as the old one, so we must rename it.
# Example: after renaming sakila.actor to sakila.actor_old (for
# example), the foreign key on film_actor looks like this:
# CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES
# CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES
# `actor_old` (`actor_id`) ON UPDATE CASCADE
# We need it to look like this instead:
# CONSTRAINT `_fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES
# CONSTRAINT `_fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES
# `actor` (`actor_id`) ON UPDATE CASCADE
# Reference the correct table name...
$constraint =~ s/REFERENCES[^\(]+/REFERENCES $orig_tbl->{name} /;
@@ -6240,6 +6293,7 @@ sub rebuild_constraints {
. "ADD $constraint";
push @rebuilt_constraints, $sql;
}
my $sql = "ALTER TABLE $child_tbl->{name} "
. join(', ', @rebuilt_constraints);
print $sql, "\n" if $o->get('print');
@@ -6693,7 +6747,7 @@ foreign keys refer to the table. The tool must update foreign keys to refer to
the new table after the schema change is complete. The tool supports two methods
for accomplishing this, and will automatically choose the appropriate method
unless you specify one explicitly. You can read more about this in the
documentation for L<"--update-foreign-keys-method">.
documentation for L<"--alter-foreign-keys-method">.
For safety, the tool does not modify the table unless you specify the
L<"--execute"> option, which is not enabled by default. The tool supports a
@@ -6751,6 +6805,66 @@ to the MySQL manual for the syntax of ALTER TABLE.
You cannot use the C<RENAME> clause to C<ALTER TABLE>, or the tool will fail.
=item --alter-foreign-keys-method
type: string
How to ensure that foreign keys point to the new table. Foreign keys that
reference the table to be altered must be treated specially to ensure that they
continue to reference the correct table. When the tool renames the original
table to let the new one take its place, by default the foreign keys "follow"
the renamed table, and must be changed to reference the new table instead.
The tool supports two techniques to achieve this. It automatically finds "child
tables" that reference the table to be altered, and chooses the best technique
automatically, but you may specify one explicitly.
=over
=item auto
Automatically determine whether to use C<rebuild_constraints> or
C<drop_swap> based on the size of all child tables compared to the
rate of rows copied per second.
=item rebuild_constraints
This method uses C<ALTER TABLE> to drop and re-add foreign key constraints that
reference the new table. This is the preferred technique, unless one or more of
the child tables is so large that the C<ALTER> would take too long. The tool
determines that by comparing the number of rows in the child table to the rate
at which the tool is able to copy rows from the old table to the new table. If
the tool estimates that the child table can be altered in less time than the
L<"--chunk-time">, then it will use this technique. For purposes of estimating
the time required to alter the child table, the tool multiplies the row-copying
rate by L<"--chunk-size-limit">, because MySQL's C<ALTER TABLE> is typically
much faster than the external process of copying rows.
Due to a limitation in MySQL, foreign keys will not have the same names after
the ALTER that they did prior to it. The tool has to rename the foreign key when
it redefines it, by adding a leading underscore.
=item drop_swap
Disable foreign key checks (FOREIGN_KEY_CHECKS=0) then drop the original table
before renaming the new table into its place. This is different from the normal
method of swapping the old and new table, which uses an atomic C<RENAME> that is
undetectable to client applications.
This method is faster and does not block, but it is riskier for two reasons.
First, for a very short time between dropping the original table and renaming
the temporary table, the table to be altered simply does not exist, and queries
against it will result in an error. Secondly, if there is an error and the new
table cannot be renamed into the place of the old one, then it is too late to
abort, because the old table is gone permanently.
=item none
This method is like C<drop_swap> without the "swap". It leaves child table
foreign keys broken.
=back
=item --ask-pass
Prompt for a password when connecting to MySQL.
@@ -6845,7 +6959,7 @@ of rows in the chunk. You can disable oversized chunk checking by specifying a
value of 0.
The tool also uses this option to determine how to handle foreign keys that
reference the table to be altered. See L<"--update-foreign-keys-method"> for
reference the table to be altered. See L<"--alter-foreign-keys-method"> for
details.
=item --chunk-time
@@ -7101,55 +7215,6 @@ online schema change process by making the table with the new schema take the
place of the original table. The original table becomes the "old table," and
the tool drops it unless you disable L<"--[no]drop-old-table">.
=item --update-foreign-keys-method
type: string
How to ensure that foreign keys point to the new table. Foreign keys that
reference the table to be altered must be treated specially to ensure that they
continue to reference the correct table. When the tool renames the original
table to let the new one take its place, by default the foreign keys "follow"
the renamed table, and must be changed to reference the new table instead.
The tool supports two techniques to achieve this. It automatically finds "child
tables" that reference the table to be altered, and chooses the best technique
automatically, but you may specify one explicitly.
=over
=item rebuild_constraints
This method uses C<ALTER TABLE> to drop and re-add foreign key constraints that
reference the new table. This is the preferred technique, unless one or more of
the child tables is so large that the C<ALTER> would take too long. The tool
determines that by comparing the number of rows in the child table to the rate
at which the tool is able to copy rows from the old table to the new table. If
the tool estimates that the child table can be altered in less time than the
L<"--chunk-time">, then it will use this technique. For purposes of estimating
the time required to alter the child table, the tool multiplies the row-copying
rate by L<"--chunk-size-limit">, because MySQL's C<ALTER TABLE> is typically
much faster than the external process of copying rows.
Due to a limitation in MySQL, foreign keys will not have the same names after
the ALTER that they did prior to it. The tool has to rename the foreign key when
it redefines it, by adding a leading underscore.
=item drop_swap
Disable foreign key checks (FOREIGN_KEY_CHECKS=0) then drop the original table
before renaming the new table into its place. This is different from the normal
method of swapping the old and new table, which uses an atomic C<RENAME> that is
undetectable to client applications.
This method is faster and does not block, but it is riskier for two reasons.
First, for a very short time between dropping the original table and renaming the
temporary table, the table to be altered simply does not exist, and queries
against it will result in an error. Secondly, if there is an error and the new
table cannot be renamed into the place of the old one, then it is too late to
abort, because the old table is gone permanently.
=back
=item --user
short form: -u; type: string

View File

@@ -32,7 +32,7 @@ elsif ( !$slave_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave';
}
else {
plan tests => 55;
plan tests => 52;
}
my $q = new Quoter();
@@ -52,7 +52,7 @@ $sb->load_file('master', "$sample/basic_no_fks.sql");
PerconaTest::wait_for_table($slave_dbh, "pt_osc.t", "id=20");
$output = output(
sub { $exit = pt_online_schema_change::main(@args, "$dsn,t=pt_osc.t",
sub { $exit = pt_online_schema_change::main(@args, "$dsn,D=pt_osc,t=t",
'--alter', 'drop column id') }
);
@@ -60,7 +60,7 @@ like(
$output,
qr/neither --dry-run nor --execute was specified/,
"Doesn't run without --execute (bug 933232)"
);
) or warn $output;
my $ddl = $master_dbh->selectrow_arrayref("show create table pt_osc.t");
like(
@@ -71,8 +71,8 @@ like(
is(
$exit,
0,
"Exit 0"
1,
"Exit 1"
);
# #############################################################################
@@ -120,8 +120,9 @@ sub test_alter_table {
my $orig_tbls = $master_dbh->selectall_arrayref(
"SHOW TABLES FROM `$db`");
my $fk_method = $args{check_fks};
my @orig_fks;
if ( $args{check_fks} ) {
if ( $fk_method ) {
foreach my $tbl ( @$orig_tbls ) {
my $fks = $tp->get_fks(
$tp->get_create_table($master_dbh, $db, $tbl->[0]));
@@ -135,17 +136,20 @@ sub test_alter_table {
$output = output(
sub { $exit = pt_online_schema_change::main(
@args,
'--print',
"$dsn,D=$db,t=$tbl",
@$cmds,
)},
stderr => 1,
);
my $fail = 0;
is(
$exit,
0,
"$name exit 0"
);
) or $fail = 1;
# There should be no new or missing tables.
my $new_tbls = $master_dbh->selectall_arrayref("SHOW TABLES FROM `$db`");
@@ -153,7 +157,7 @@ sub test_alter_table {
$new_tbls,
$orig_tbls,
"$name tables"
);
) or $fail = 1;
# Rows in the original and new table should be identical.
my $new_rows = $master_dbh->selectall_arrayref("SELECT * FROM $table ORDER BY `$pk_col`");
@@ -161,7 +165,7 @@ sub test_alter_table {
$new_rows,
$orig_rows,
"$name rows"
);
) or $fail = 1;
# Check if the ALTER was actually done.
if ( $test_type eq 'drop_col' ) {
@@ -172,14 +176,14 @@ sub test_alter_table {
$ddl,
qr/^\s+$col\s+/m,
"$name ALTER DROP COLUMN=$args{drop_col} (dry run)"
);
) or $fail = 1;
}
else {
unlike(
$ddl,
qr/^\s+$col\s+/m,
"$name ALTER DROP COLUMN=$args{drop_col}"
);
) or $fail = 1;
}
}
elsif ( $test_type eq 'add_col' ) {
@@ -193,22 +197,54 @@ sub test_alter_table {
lc($rows->{$tbl}->{engine}),
$new_engine,
"$name ALTER ENGINE=$args{new_engine}"
);
) or $fail = 1;
}
if ( $args{check_fks} ) {
if ( $fk_method ) {
my @new_fks;
my $rebuild_method = 0;
foreach my $tbl ( @$orig_tbls ) {
my $fks = $tp->get_fks(
$tp->get_create_table($master_dbh, $db, $tbl->[0]));
push @new_fks, $fks;
# The tool does not use the same/original fk name,
# it appends a single _. So we need to strip this
# to compare the original fks to the new fks.
if ( $fk_method eq 'rebuild_constraints' ) {
my %new_fks = map {
my $real_fk_name = $_;
my $fk_name = $_;
if ( $fk_name =~ s/^_// ) {
$rebuild_method = 1;
}
$fks->{$real_fk_name}->{name} =~ s/^_//;
$fks->{$real_fk_name}->{ddl} =~ s/`$real_fk_name`/`$fk_name`/;
$fk_name => $fks->{$real_fk_name};
} keys %$fks;
push @new_fks, \%new_fks;
}
else {
# drop_swap
push @new_fks, $fks;
}
}
if ( grep { $_ eq '--execute' } @$cmds ) {
ok(
$fk_method eq 'rebuild_constraints' && $rebuild_method ? 1
: $fk_method eq 'drop_swap' && !$rebuild_method ? 1
: 0,
"$name FK $fk_method method"
);
}
is_deeply(
\@new_fks,
\@orig_fks,
"$name FK constraints"
);
) or $fail = 1;
# Go that extra mile and verify that the fks are actually
# still functiona: i.e. that they'll prevent us from delete
@@ -221,7 +257,11 @@ sub test_alter_table {
$EVAL_ERROR,
qr/foreign key constraint fails/,
"$name FK constraints still hold"
);
) or $fail = 1;
}
if ( $fail ) {
diag("Output from failed test:\n$output");
}
return;
@@ -281,11 +321,11 @@ test_alter_table(
wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
check_fks => "rebuild_constraints",
cmds => [
qw(
--dry-run
--update-foreign-keys-method rebuild_constraints
--alter-foreign-keys-method rebuild_constraints
),
'--alter', 'DROP COLUMN last_update',
],
@@ -300,11 +340,11 @@ test_alter_table(
# wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
check_fks => "rebuild_constraints",
cmds => [
qw(
--execute
--update-foreign-keys-method rebuild_constraints
--alter-foreign-keys-method rebuild_constraints
),
'--alter', 'DROP COLUMN last_update',
],
@@ -316,25 +356,25 @@ test_alter_table(
# Somewhat dangerous, but quick. Downside: table doesn't exist for a moment.
test_alter_table(
name => "Basic FK drop-swap --dry-run",
name => "Basic FK drop_swap --dry-run",
table => "pt_osc.country",
pk_col => "country_id",
file => "basic_with_fks.sql",
wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
check_fks => "drop_swap",
cmds => [
qw(
--dry-run
--update-foreign-keys-method drop_swap
--alter-foreign-keys-method drop_swap
),
'--alter', 'DROP COLUMN last_update',
],
);
test_alter_table(
name => "Basic FK drop-swap --execute",
name => "Basic FK drop_swap --execute",
table => "pt_osc.country",
pk_col => "country_id",
# The previous test should not have modified the table.
@@ -342,48 +382,35 @@ test_alter_table(
# wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
check_fks => "drop_swap",
cmds => [
qw(
--execute
--update-foreign-keys-method drop_swap
--alter-foreign-keys-method drop_swap
),
'--alter', 'DROP COLUMN last_update',
],
);
# Let the tool auto-determine the fk update method.
# Let the tool auto-determine the fk update method. This should choose
# the rebuild_constraints method because the tables are quite small.
# This is tested by indicating the rebuild_constraints method, which
# causes the test sub to verify that the fks have leading _; they won't
# if drop_swap was used. To verify this, change auto to drop_swap
# and this test will fail.
test_alter_table(
name => "Basic FK auto --execute",
table => "pt_osc.country",
pk_col => "country_id",
file => "basic_with_fks.sql",
wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
cmds => [
name => "Basic FK auto --execute",
table => "pt_osc.country",
pk_col => "country_id",
file => "basic_with_fks.sql",
wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => "rebuild_constraints",
cmds => [
qw(
--execute
),
'--alter', 'DROP COLUMN last_update',
],
);
# Specify the child tables manually.
test_alter_table(
name => "Basic FK with given child tables",
table => "pt_osc.country",
pk_col => "country_id",
file => "basic_with_fks.sql",
wait => ["pt_osc.address", "address_id=5"],
test_type => "drop_col",
drop_col => "last_update",
check_fks => 1,
cmds => [
qw(
--execute
--child-tables city
--alter-foreign-keys-method auto
),
'--alter', 'DROP COLUMN last_update',
],
@@ -404,24 +431,31 @@ sub test_table {
my $org_rows = $master_dbh->selectall_arrayref('select * from osc.t order by id');
output(
$output = output(
sub { $exit = pt_online_schema_change::main(@args,
"$dsn,D=osc,t=t", qw(--alter ENGINE=InnoDB)) },
"$dsn,D=osc,t=t", qw(--execute --alter ENGINE=InnoDB)) },
stderr => 1,
);
my $new_rows = $master_dbh->selectall_arrayref('select * from osc.t order by id');
my $fail = 0;
is_deeply(
$new_rows,
$org_rows,
"$name rows"
);
) or $fail = 1;
is(
$exit,
0,
"$name exit status 0"
);
) or $fail = 1;
if ( $fail ) {
diag("Output from failed test:\n$output");
}
}
test_table(

View File

@@ -48,14 +48,14 @@ my $rows;
# Of course, the orig database and table must exist.
throws_ok(
sub { pt_online_schema_change::main(@args,
"$dsn,t=nonexistent_db.t", qw(--dry-run)) },
qr/`nonexistent_db`.`t` does not exist/,
"$dsn,D=nonexistent_db,t=t", qw(--dry-run)) },
qr/Unknown database/,
"Original database must exist"
);
throws_ok(
sub { pt_online_schema_change::main(@args,
"$dsn,t=mysql.nonexistent_tbl", qw(--dry-run)) },
"$dsn,D=mysql,t=nonexistent_tbl", qw(--dry-run)) },
qr/`mysql`.`nonexistent_tbl` does not exist/,
"Original table must exist"
);
@@ -69,7 +69,7 @@ $slave_dbh->do("USE pt_osc");
$master_dbh->do("CREATE TRIGGER pt_osc.pt_osc_test AFTER DELETE ON pt_osc.t FOR EACH ROW DELETE FROM pt_osc.t WHERE 0");
throws_ok(
sub { pt_online_schema_change::main(@args,
"$dsn,t=pt_osc.t", qw(--dry-run)) },
"$dsn,D=pt_osc,t=t", qw(--dry-run)) },
qr/`pt_osc`.`t` has triggers/,
"Original table cannot have triggers"
);
@@ -80,7 +80,7 @@ $master_dbh->do("ALTER TABLE pt_osc.t DROP COLUMN id");
$master_dbh->do("ALTER TABLE pt_osc.t DROP INDEX c");
throws_ok(
sub { pt_online_schema_change::main(@args,
"$dsn,t=pt_osc.t", qw(--dry-run)) },
"$dsn,D=pt_osc,t=t", qw(--dry-run)) },
qr/`pt_osc`.`t` does not have a PRIMARY KEY or a unique index/,
"Original table must have a PK or unique index"
);
@@ -101,7 +101,7 @@ for my $i ( 1..10 ) {
throws_ok(
sub { pt_online_schema_change::main(@args,
"$dsn,t=pt_osc.t", qw(--quiet --dry-run)) },
"$dsn,D=pt_osc,t=t", qw(--quiet --dry-run)) },
qr/Failed to find a unique new table name/,
"Doesn't try forever to find a new table name"
);