diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index ee79da28..36bdd3a7 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -9102,6 +9102,15 @@ sub main { $child_table->{name}, $child_table->{row_est} || '?'; } + + # TODO: Fix self referencing foreign keys handling. + # See: https://jira.percona.com/browse/PT-1802 + # https://jira.percona.com/browse/PT-1853 + if (has_self_ref_fks($orig_tbl->{db}, $orig_tbl->{tbl}, $child_tables) and $o->get('check-foreign-keys')) { + print "The table has self referencing foreign keys and that might lead to errors.\n"; + print "Use --no-check-foreign-keys to disable this check.\n"; + return 1 + } if ( $alter_fk_method ) { # Let the user know how we're going to update the child table @@ -10396,6 +10405,20 @@ sub check_alter { return; } +sub has_self_ref_fks { + my ($orig_db, $orig_table, $child_tables) = @_; + + my $db_tbl = sprintf("`%s`.`%s`", $orig_db, $orig_table); + + foreach my $child_table ( @$child_tables ) { + if ($db_tbl eq $child_table->{name}) { + return 1; + } + }; + + return undef; +} + # This function tries to detect if the --alter param is adding unique indexes. # It returns an array of arrays, having a list of fields for each unique index # found. @@ -12168,6 +12191,15 @@ L<"--print"> and verify that the triggers are correct. =back +=item --[no]check-foreign-keys + +default: yes + +Check for self referencing foreing keys. Currently self referencing FKs are +not fully supported so to prevent errors, this program wont't run if the table +has self referen foreign keys. Use this parameter to disable self referencing +FK checks. + =item --check-interval type: time; default: 1 diff --git a/t/pt-online-schema-change/pt-1853.t b/t/pt-online-schema-change/pt-1853.t new file mode 100644 index 00000000..0db37a72 --- /dev/null +++ b/t/pt-online-schema-change/pt-1853.t @@ -0,0 +1,80 @@ +#!/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 threads; +use threads::shared; +use Thread::Semaphore; + +use English qw(-no_match_vars); +use Test::More; + +use Data::Dumper; +use PerconaTest; +use Sandbox; +use SqlModes; +use File::Temp qw/ tempdir /; + +require "$trunk/bin/pt-online-schema-change"; + +plan tests => 3; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $master_dbh = $sb->get_dbh_for("master"); +my $master_dsn = $sb->dsn_for("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 @args = (qw(--set-vars innodb_lock_wait_timeout=3)); +my $output; +my $exit_status; + +$sb->load_file('master', "t/pt-online-schema-change/samples/pt-1853.sql"); + +($output, $exit_status) = full_output( + sub { pt_online_schema_change::main(@args, "$master_dsn,D=test,t=jointit", + '--execute', + '--alter', "engine=innodb", + '--alter-foreign-keys-method', 'rebuild_constraints' + ), + }, + stderr => 1, +); + +isnt( + $exit_status, + 0, + "PT-1853, there are self referencing FKs -> exit status != 0", +); + +($output, $exit_status) = full_output( + sub { pt_online_schema_change::main(@args, "$master_dsn,D=test,t=jointit", + '--execute', + '--alter', "engine=innodb", + '--alter-foreign-keys-method', 'rebuild_constraints', + '--no-check-foreign-keys' + ), + }, + stderr => 1, +); + +isnt( + $exit_status, + 0, + "PT-1853, there are self referencing FKs but --no-check-foreign-keys was specifid -> exit status = 0", +); + +# ############################################################################# +# 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-1853.sql b/t/pt-online-schema-change/samples/pt-1853.sql new file mode 100644 index 00000000..cc484565 --- /dev/null +++ b/t/pt-online-schema-change/samples/pt-1853.sql @@ -0,0 +1,19 @@ +DROP DATABASE IF EXISTS test; +CREATE DATABASE test; + +USE test; + +CREATE TABLE t1 ( +id int, +f1 int +); + +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;