diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index 059f79aa..6d965a9d 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -8145,17 +8145,35 @@ sub check_repl_table { my $sql = "SHOW DATABASES LIKE '$db'"; PTDEBUG && _d($sql); my @db_exists = $dbh->selectrow_array($sql); - if ( !@db_exists && $o->get('create-replicate-table') ) { - $sql = "CREATE DATABASE " . $q->quote($db) . " /* pt-table-checksum */"; + if ( !@db_exists && !$o->get('create-replicate-table') ) { + die "--replicate database $db does not exist and " + . "--no-create-replicate-table was passed in. You need " + . "to create the database.\n"; + } + + if ( $o->get('create-replicate-table') ) { + $sql = "CREATE DATABASE IF NOT EXISTS " + . $q->quote($db) + . " /* pt-table-checksum */"; + local $@; + PTDEBUG && _d($sql); eval { $dbh->do($sql); }; if ( $EVAL_ERROR ) { - die "--replicate database $db does not exist and it cannot be " - . "created automatically. You need to create the database.\n"; + if ( @db_exists ) { + print STDERR "CREATE DATABASE IF NOT EXISTS $db failed, but the " + . "db already exists. This is harmless unless the " + . "slaves don't have the database. $EVAL_ERROR"; # kb link? + } + else { + die "--replicate database $db does not exist and it cannot be " + . "created automatically. You need to create the database. " + . $EVAL_ERROR; + } } } - + # USE the correct db (probably the repl db, but maybe --replicate-database). use_repl_db(%args); @@ -8165,28 +8183,41 @@ sub check_repl_table { db => $db, tbl => $tbl, ); - if ( !$tbl_exists ) { - if ( $o->get('create-replicate-table') ) { - create_repl_table(%args) - } - else { - die "--replicate table $repl_table does not exist; " - . "read the documentation or use --create-replicate-table " - . "to create it.\n"; + + # Always create the table, unless --no-create-replicate-table + # was passed in; see https://bugs.launchpad.net/percona-toolkit/+bug/950294 + if ( !$tbl_exists && !$o->get('create-replicate-table') ) { + die "--replicate table $repl_table does not exist and " + . "--no-create-replicate-table was passed in. " + . "You need to create the table.\n"; + } + if ( $o->get('create-replicate-table') ) { + local $@; + eval { + create_repl_table(%args); + }; + if ( $EVAL_ERROR ) { + if ( $tbl_exists ) { + print STDERR "CREATE TABLE IF NOT EXISTS $args{repl_table} " + . "failed, but the table already exists. This " + . "is harmless unless the slaves don't have the " + . "table. $EVAL_ERROR"; + } + else { + die $EVAL_ERROR; + } } } - else { - PTDEBUG && _d('--replicate table', $repl_table, 'already exists'); - # Check it again but this time check the privs. - my $have_tbl_privs = $tp->check_table( - dbh => $dbh, - db => $db, - tbl => $tbl, - all_privs => 1, - ); - die "User does not have all privileges on --replicate table " - . "$repl_table.\n" unless $have_tbl_privs; - } + + # Check it again but this time check the privs. + my $have_tbl_privs = $tp->check_table( + dbh => $dbh, + db => $db, + tbl => $tbl, + all_privs => 1, + ); + die "User does not have all privileges on --replicate table " + . "$repl_table.\n" unless $have_tbl_privs; # Check and wait for the repl table to appear on all slaves. # https://bugs.launchpad.net/percona-toolkit/+bug/1008778 @@ -8327,7 +8358,7 @@ sub create_repl_table { my ($dbh, $repl_table, $o) = @args{@required_args}; PTDEBUG && _d('Creating --replicate table', $repl_table); my $sql = $o->read_para_after(__FILE__, qr/MAGIC_create_replicate/); - $sql =~ s/CREATE TABLE checksums/CREATE TABLE $repl_table/; + $sql =~ s/CREATE TABLE checksums/CREATE TABLE IF NOT EXISTS $repl_table/; $sql =~ s/;$//; PTDEBUG && _d($dbh, $sql); eval { diff --git a/t/pt-table-checksum/privs.t b/t/pt-table-checksum/privs.t index 79db0b13..4b94c07b 100644 --- a/t/pt-table-checksum/privs.t +++ b/t/pt-table-checksum/privs.t @@ -41,9 +41,6 @@ elsif ( !$slave1_dbh ) { elsif ( !@{$master_dbh->selectall_arrayref("show databases like 'sakila'")} ) { plan skip_all => 'sakila database is not loaded'; } -else { - plan tests => 3; -} # The sandbox servers run with lock_wait_timeout=3 and it's not dynamic # so we need to specify --lock-wait-timeout=3 else the tool will die. @@ -54,6 +51,49 @@ my $output; my $exit_status; my $sample = "t/pt-table-checksum/samples/"; +# ############################################################################ +# Should always create schema and tables with IF NOT EXISTS +# https://bugs.launchpad.net/percona-toolkit/+bug/950294 +# ############################################################################ + +$sb->wipe_clean($master_dbh); +diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql 2>/dev/null`); +PerconaTest::wait_for_table($slave1_dbh, "mysql.tables_priv", "user='ro_checksum_user'"); + +($output, $exit_status) = full_output( + sub { pt_table_checksum::main(@args, + "$master_dsn,u=ro_checksum_user,p=msandbox", + qw(--recursion-method none) + ) }, +); + +isnt($exit_status, 0, ""); +like($output, + qr/\Q--replicate database percona does not exist and it cannot be created automatically/, + "fails if the percona db doesn't exist and the user can't create it", +); + +($output, $exit_status) = full_output( + sub { pt_table_checksum::main(@args, + "$master_dsn,u=ro_checksum_user,p=msandbox", + qw(--recursion-method none --no-create-replicate-table) + ) }, +); + +like($output, + qr/\Q--replicate database percona does not exist and --no-create-replicate-table was/, + "fails if the percona db doesn't exist and --no-create-replicate-table", +); + +diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`); +wait_until( + sub { + my $rows=$slave2_dbh->selectall_arrayref("SELECT user FROM mysql.user"); + return !grep { ($_->[0] || '') ne 'ro_checksum_user' } @$rows; + } +); +$sb->wipe_clean($master_dbh); + # ############################################################################ # --recursion-method=none to avoid SHOW SLAVE HOSTS # https://bugs.launchpad.net/percona-toolkit/+bug/987694 @@ -64,7 +104,7 @@ pt_table_checksum::main(@args, "$master_dsn,u=msandbox,p=msandbox", qw(-t sakila.country --quiet --quiet)); -diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql`); +diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql 2>/dev/null`); PerconaTest::wait_for_table($slave1_dbh, "mysql.tables_priv", "user='ro_checksum_user'"); $output = output( @@ -90,6 +130,20 @@ like( "Read-only user (bug 987694): checksummed rows" ); +diag(qx{/tmp/12345/use -u root -e 'DROP TABLE `percona`.`checksums`'}); + +($output, $exit_status) = full_output( + sub { pt_table_checksum::main(@args, + "$master_dsn,u=ro_checksum_user,p=msandbox", + qw(--recursion-method none --no-create-replicate-table) + ) }, +); + +like($output, + qr/\Q--replicate table `percona`.`checksums` does not exist and --no/, + "fails if the checksums db doesn't exist and --no-create-replicate-table" +); + diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`); wait_until( sub { @@ -103,4 +157,5 @@ wait_until( # ############################################################################# $sb->wipe_clean($master_dbh); ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); -exit; + +done_testing;