diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 63a44a47..4b500b5a 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -11134,7 +11134,7 @@ sub rebuild_constraints { if ($fk =~ /^__/) { ($new_fk = $fk) =~ s/^__//; } else { - $new_fk = '_'.$fk; + $new_fk = '___'.$fk; } PTDEBUG && _d("Old FK name: $fk New FK name: $new_fk"); diff --git a/t/pt-online-schema-change/rename_self_ref_fk_constraints.t b/t/pt-online-schema-change/rename_self_ref_fk_constraints.t index e402e281..ce1b421b 100644 --- a/t/pt-online-schema-change/rename_self_ref_fk_constraints.t +++ b/t/pt-online-schema-change/rename_self_ref_fk_constraints.t @@ -32,7 +32,6 @@ my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox'; my @args = (qw(--set-vars innodb_lock_wait_timeout=3 --alter-foreign-keys-method rebuild_constraints)); my $output; my $exit_status; -my $sample = "t/pt-online-schema-change/samples/"; # ############################################################################ # https://bugs.launchpad.net/percona-toolkit/+bug/1632522 @@ -40,7 +39,7 @@ my $sample = "t/pt-online-schema-change/samples/"; # ############################################################################ diag("Before loading sql"); -$sb->load_file('master', "$sample/bug-1632522.sql"); +$sb->load_file('master', "t/pt-online-schema-change/samples/bug-1632522.sql"); diag("after loading sql"); # run once: we expect the constraint name to be appended with one underscore @@ -52,7 +51,15 @@ diag("after loading sql"); qw(--execute)) }, ); -my $constraints = $master_dbh->selectall_arrayref("SELECT TABLE_NAME, CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema='bug1632522' and (TABLE_NAME='test_table' OR TABLE_NAME='person') and CONSTRAINT_NAME LIKE '%fk_%' ORDER BY TABLE_NAME, CONSTRAINT_NAME"); +my $query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + AND (TABLE_NAME='test_table' OR TABLE_NAME='person') + AND CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +my $constraints = $master_dbh->selectall_arrayref($query); is_deeply( $constraints, @@ -73,7 +80,15 @@ is_deeply( qw(--execute)) }, ); -$constraints = $master_dbh->selectall_arrayref("SELECT TABLE_NAME, CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema='bug1632522' and (TABLE_NAME='test_table' OR TABLE_NAME='person') and CONSTRAINT_NAME LIKE '%fk_%' ORDER BY TABLE_NAME, CONSTRAINT_NAME"); +$query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + AND (TABLE_NAME='test_table' OR TABLE_NAME='person') + AND CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +$constraints = $master_dbh->selectall_arrayref($query); is_deeply( @@ -94,7 +109,15 @@ is_deeply( qw(--execute)) }, ); -$constraints = $master_dbh->selectall_arrayref("SELECT TABLE_NAME, CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE table_schema='bug1632522' and (TABLE_NAME='test_table' OR TABLE_NAME='person') and CONSTRAINT_NAME LIKE '%fk_%' ORDER BY TABLE_NAME, CONSTRAINT_NAME"); +$query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + and (TABLE_NAME='test_table' OR TABLE_NAME='person') + and CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +$constraints = $master_dbh->selectall_arrayref($query); is_deeply( diff --git a/t/pt-online-schema-change/rename_self_ref_fk_constraints_pt_1802.t b/t/pt-online-schema-change/rename_self_ref_fk_constraints_pt_1802.t new file mode 100644 index 00000000..ce1b421b --- /dev/null +++ b/t/pt-online-schema-change/rename_self_ref_fk_constraints_pt_1802.t @@ -0,0 +1,138 @@ +#!/usr/bin/env perl + +BEGIN { + die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" + unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; + unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; +}; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Test::More; + +use Data::Dumper; +use PerconaTest; +use Sandbox; + +require "$trunk/bin/pt-online-schema-change"; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $master_dbh = $sb->get_dbh_for('master'); + +if ( !$master_dbh ) { + plan skip_all => 'Cannot connect to sandbox master'; +} + +# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic +# so we need to specify --set-vars innodb_lock_wait_timeout-3 else the +# tool will die. +my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox'; +my @args = (qw(--set-vars innodb_lock_wait_timeout=3 --alter-foreign-keys-method rebuild_constraints)); +my $output; +my $exit_status; + +# ############################################################################ +# https://bugs.launchpad.net/percona-toolkit/+bug/1632522 +# pt-online-schema-change fails with duplicate key in table for self-referencing FK +# ############################################################################ + +diag("Before loading sql"); +$sb->load_file('master', "t/pt-online-schema-change/samples/bug-1632522.sql"); +diag("after loading sql"); + +# run once: we expect the constraint name to be appended with one underscore +# but the self-referencing constraint will have 2 underscore +($output, $exit_status) = full_output( + sub { pt_online_schema_change::main(@args, + "$master_dsn,D=bug1632522,t=test_table", + "--alter", "ENGINE=InnoDB", + qw(--execute)) }, +); + +my $query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + AND (TABLE_NAME='test_table' OR TABLE_NAME='person') + AND CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +my $constraints = $master_dbh->selectall_arrayref($query); + +is_deeply( + $constraints, + [ + ['person', '_fk_testId'], + ['test_table', 'fk_person'], + ['test_table', 'fk_refId'], + ], + "First run adds or removes underscore from constraint names, accordingly" +); + +# run second time: we expect constraint names to be prefixed with one underscore +# if they havre't one, and to remove 2 if they have 2 +($output, $exit_status) = full_output( + sub { pt_online_schema_change::main(@args, + "$master_dsn,D=bug1632522,t=test_table", + "--alter", "ENGINE=InnoDB", + qw(--execute)) }, +); + +$query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + AND (TABLE_NAME='test_table' OR TABLE_NAME='person') + AND CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +$constraints = $master_dbh->selectall_arrayref($query); + + +is_deeply( + $constraints, + [ + ['person', '_fk_testId'], + ['test_table', 'fk_person'], + ['test_table', 'fk_refId'], + ], + "Second run self-referencing will be one due to rebuild_constraints" +); + +# run third time: we expect constraints to be the same as we started (toggled back) +($output, $exit_status) = full_output( + sub { pt_online_schema_change::main(@args, + "$master_dsn,D=bug1632522,t=test_table", + "--alter", "ENGINE=InnoDB", + qw(--execute)) }, +); + +$query = <<"END"; + SELECT TABLE_NAME, CONSTRAINT_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE table_schema='bug1632522' + and (TABLE_NAME='test_table' OR TABLE_NAME='person') + and CONSTRAINT_NAME LIKE '%fk_%' +ORDER BY TABLE_NAME, CONSTRAINT_NAME +END +$constraints = $master_dbh->selectall_arrayref($query); + + +is_deeply( + $constraints, + [ + ['person', '_fk_testId'], + ['test_table', 'fk_person'], + ['test_table', 'fk_refId'], + ], + "Third run toggles constraint names back to how they were" +); + +# ############################################################################# +# Done. +# ############################################################################# +$sb->wipe_clean($master_dbh); +ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); +done_testing; diff --git a/t/pt-online-schema-change/samples/pt-1802.sql b/t/pt-online-schema-change/samples/pt-1802.sql new file mode 100644 index 00000000..4d8a0825 --- /dev/null +++ b/t/pt-online-schema-change/samples/pt-1802.sql @@ -0,0 +1,9 @@ +CREATE TABLE `joinit` ( +`i` int(11) NOT NULL AUTO_INCREMENT, +`s` varchar(64) DEFAULT NULL, +`t` time NOT NULL, +`g` int(11) NOT NULL, +`j` int(11) NOT NULL DEFAULT 1, +PRIMARY KEY (`i`)) +ENGINE=InnoDB; +ALTER TABLE joinit ADD FOREIGN KEY i_fk (j) REFERENCES joinit (i) ON UPDATE cascade ON DELETE restrict;