Merge pk-del-bug-1103672-encore.

This commit is contained in:
Daniel Nichter
2013-01-30 08:07:19 -07:00
4 changed files with 216 additions and 14 deletions

View File

@@ -8370,19 +8370,74 @@ sub main {
# Find a pk or unique index to use for the delete trigger. can_nibble()
# above returns an index, but NibbleIterator will use non-unique indexes,
# so we have to do this again here.
my $indexes = $new_tbl->{tbl_struct}->{keys}; # brevity
foreach my $index ( $tp->sort_indexes($new_tbl->{tbl_struct}) ) {
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
PTDEBUG && _d('Delete trigger index:', Dumper($index));
$new_tbl->{del_index} = $index;
last;
{
my $indexes = $new_tbl->{tbl_struct}->{keys}; # brevity
foreach my $index ( $tp->sort_indexes($new_tbl->{tbl_struct}) ) {
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
PTDEBUG && _d('Delete trigger new index:', Dumper($index));
$new_tbl->{del_index} = $index;
last;
}
}
PTDEBUG && _d('New table delete index:', $new_tbl->{del_index});
}
{
my $indexes = $orig_tbl->{tbl_struct}->{keys}; # brevity
foreach my $index ( $tp->sort_indexes($orig_tbl->{tbl_struct}) ) {
if ( $index eq 'PRIMARY' || $indexes->{$index}->{is_unique} ) {
PTDEBUG && _d('Delete trigger orig index:', Dumper($index));
$orig_tbl->{del_index} = $index;
last;
}
}
PTDEBUG && _d('Orig table delete index:', $orig_tbl->{del_index});
}
if ( !$new_tbl->{del_index} ) {
die "The new table $new_tbl->{name} does not have a PRIMARY KEY "
. "or a unique index which is required for the DELETE trigger.\n";
}
# Determine whether to use the new or orig table delete index.
# The new table del index is preferred due to
# https://bugs.launchpad.net/percona-toolkit/+bug/1062324
# In short, if the chosen del index is re-created with new columns,
# its original columns may be dropped, so just use its new columns.
# But, due to https://bugs.launchpad.net/percona-toolkit/+bug/1103672,
# the chosen del index on the new table may reference columns which
# do not/no longer exist in the orig table, so we check for this
# and, if it's the case, we fall back to using the del index from
# the orig table.
my $del_tbl = $new_tbl; # preferred
my $new_del_index_cols # brevity
= $new_tbl->{tbl_struct}->{keys}->{ $new_tbl->{del_index} }->{cols};
foreach my $new_del_index_col ( @$new_del_index_cols ) {
if ( !exists $orig_cols->{$new_del_index_col} ) {
if ( !$orig_tbl->{del_index} ) {
die "The new table index $new_tbl->{del_index} would be used "
. "for the DELETE trigger, but it uses column "
. "$new_del_index_col which does not exist in the original "
. "table and the original table does not have a PRIMARY KEY "
. "or a unique index to use for the DELETE trigger.\n";
}
print "Using original table index $orig_tbl->{del_index} for the "
. "DELETE trigger instead of new table index $new_tbl->{del_index} "
. "because the new table index uses column $new_del_index_col "
. "which does not exist in the original table.\n";
$del_tbl = $orig_tbl;
last;
}
}
{
my $del_cols
= $del_tbl->{tbl_struct}->{keys}->{ $del_tbl->{del_index} }->{cols};
PTDEBUG && _d('Index for delete trigger: table', $del_tbl->{name},
'index', $del_tbl->{del_index},
'columns', @$del_cols);
}
# ########################################################################
# Step 3: Create the triggers to capture changes on the original table and
# apply them to the new table.
@@ -8412,6 +8467,7 @@ sub main {
create_triggers(
orig_tbl => $orig_tbl,
new_tbl => $new_tbl,
del_tbl => $del_tbl,
columns => \@common_cols,
Cxn => $cxn,
Quoter => $q,
@@ -8930,6 +8986,28 @@ sub check_alter {
my $ok = 1;
# ########################################################################
# Check for DROP PRIMARY KEY.
# ########################################################################
if ( $alter =~ m/DROP\s+PRIMARY\s+KEY/i ) {
my $msg = "--alter contains 'DROP PRIMARY KEY'. Dropping and "
. "altering the primary key can be dangerous, "
. "especially if the original table does not have other "
. "unique indexes.\n";
if ( $dry_run ) {
print $msg;
}
else {
$ok = 0;
warn $msg
. "The tool should handle this correctly, but you should "
. "test it first and carefully examine the triggers which "
. "rely on the PRIMARY KEY or a unique index. Specify "
. "--no-check-alter to disable this check and perform the "
. "--alter.\n";
}
}
# ########################################################################
# Check for renamed columns.
# https://bugs.launchpad.net/percona-toolkit/+bug/1068562
@@ -8976,6 +9054,7 @@ sub check_alter {
}
if ( !$ok ) {
# check_alter.t relies on this output.
die "--check-alter failed.\n";
}
@@ -9536,11 +9615,11 @@ sub drop_swap {
sub create_triggers {
my ( %args ) = @_;
my @required_args = qw(orig_tbl new_tbl columns Cxn Quoter OptionParser);
my @required_args = qw(orig_tbl new_tbl del_tbl columns Cxn Quoter OptionParser);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($orig_tbl, $new_tbl, $cols, $cxn, $q, $o) = @args{@required_args};
my ($orig_tbl, $new_tbl, $del_tbl, $cols, $cxn, $q, $o) = @args{@required_args};
# This sub works for --dry-run and --execute. With --dry-run it's
# only interesting if --print is specified, too; then the user can
@@ -9569,8 +9648,8 @@ sub create_triggers {
# unique indexes can be nullable. Cols are from the new table and
# they may have been renamed
my %old_col_for = map { $_->{new} => $_->{old} } @$cols;
my $tbl_struct = $new_tbl->{tbl_struct};
my $del_index = $new_tbl->{del_index};
my $tbl_struct = $del_tbl->{tbl_struct};
my $del_index = $del_tbl->{del_index};
my $del_index_cols = join(" AND ", map {
my $new_col = $_;
my $old_col = $old_col_for{$new_col} || $new_col;
@@ -10226,9 +10305,19 @@ In previous versions of the tool, renaming a column with
C<CHANGE COLUMN name new_name> would lead to that column's data being lost.
The tool now parses the alter statement and tries to catch these cases, so
the renamed columns should have the same data as the originals. However, the
code that does this is not a full-blown SQL parser, so we recommend that users
run the tool with L<"--dry-run"> and check if it's detecting the renames
correctly.
code that does this is not a full-blown SQL parser, so you should first
run the tool with L<"--dry-run"> and L<"--print"> and verify that it detects
the renamed columns correctly.
=item DROP PRIMARY KEY
If L<"--alter"> contain C<DROP PRIMARY KEY> (case- and space-insensitive),
a warning is printed and the tool exits unless L<"--dry-run"> is specified.
Altering the primary key can be dangerous, but the tool can handle it.
The tool's triggers, particularly the DELETE trigger, are most affected by
altering the primary key because the tool prefers to use the primary key
for its triggers. You should first run the tool with L<"--dry-run"> and
L<"--print"> and verify that the triggers are correct.
=back