From 96665fd9ccda9d9c129c5e421b10d00ccf78e5de Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Sep 2009 14:24:19 +0800 Subject: [PATCH] BUG#43579 mysql_upgrade tries to alter log tables on replicated database All statements executed by mysql_upgrade are binlogged and then are replicated to slave. This will result in some errors. The report of this bug has demonstrated some examples. Master and slave should be upgraded separately. All statements executed by mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog options are added into mysql_upgrade. These options control whether sql statements are binlogged or not. --- client/mysql_upgrade.c | 27 +++++++++ client/mysqlcheck.c | 19 +++++++ mysql-test/include/have_mysql_upgrade.inc | 4 ++ .../suite/rpl/r/rpl_mysql_upgrade.result | 13 +++++ mysql-test/suite/rpl/t/rpl_mysql_upgrade.test | 56 +++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 mysql-test/include/have_mysql_upgrade.inc create mode 100644 mysql-test/suite/rpl/r/rpl_mysql_upgrade.result create mode 100644 mysql-test/suite/rpl/t/rpl_mysql_upgrade.test diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index cfd7ed4ea56..52c3636219d 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -54,6 +54,8 @@ static char **defaults_argv; static my_bool not_used; /* Can't use GET_BOOL without a value pointer */ +static my_bool opt_write_binlog; + #include static struct my_option my_long_options[]= @@ -124,6 +126,11 @@ static struct my_option my_long_options[]= {"verbose", 'v', "Display more output about the process", (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"write-binlog", OPT_WRITE_BINLOG, + "All commands including mysqlcheck are binlogged. Enabled by default;" + "use --skip-write-binlog when commands should not be sent to replication slaves.", + (uchar**) &opt_write_binlog, (uchar**) &opt_write_binlog, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -448,6 +455,8 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, int ret; File fd; char query_file_path[FN_REFLEN]; + const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;"; + DBUG_ENTER("run_query"); DBUG_PRINT("enter", ("query: %s", query)); if ((fd= create_temp_file(query_file_path, opt_tmpdir, @@ -455,6 +464,22 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, MYF(MY_WME))) < 0) die("Failed to create temporary file for defaults"); + /* + Master and slave should be upgraded separately. All statements executed + by mysql_upgrade will not be binlogged. + 'SET SQL_LOG_BIN=0' is executed before any other statements. + */ + if (!opt_write_binlog) + { + if (my_write(fd, sql_log_bin, sizeof(sql_log_bin)-1, + MYF(MY_FNABP | MY_WME))) + { + my_close(fd, MYF(0)); + my_delete(query_file_path, MYF(0)); + die("Failed to write to '%s'", query_file_path); + } + } + if (my_write(fd, (uchar*) query, strlen(query), MYF(MY_FNABP | MY_WME))) { @@ -648,6 +673,7 @@ static int run_mysqlcheck_upgrade(void) "--check-upgrade", "--all-databases", "--auto-repair", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } @@ -662,6 +688,7 @@ static int run_mysqlcheck_fixnames(void) "--all-databases", "--fix-db-names", "--fix-table-names", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 82aabd77b24..1533e602639 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -652,6 +652,17 @@ static int use_db(char *database) return 0; } /* use_db */ +static int disable_binlog() +{ + const char *stmt= "SET SQL_LOG_BIN=0"; + if (mysql_query(sock, stmt)) + { + fprintf(stderr, "Failed to %s\n", stmt); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + return 1; + } + return 0; +} static int handle_request_for_tables(char *tables, uint length) { @@ -844,6 +855,14 @@ int main(int argc, char **argv) if (dbConnect(current_host, current_user, opt_password)) exit(EX_MYSQLERR); + if (!opt_write_binlog) + { + if (disable_binlog()) { + first_error= 1; + goto end; + } + } + if (opt_auto_repair && my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64)) { diff --git a/mysql-test/include/have_mysql_upgrade.inc b/mysql-test/include/have_mysql_upgrade.inc new file mode 100644 index 00000000000..8f486176018 --- /dev/null +++ b/mysql-test/include/have_mysql_upgrade.inc @@ -0,0 +1,4 @@ +--require r/have_mysql_upgrade.result +--disable_query_log +select LENGTH("$MYSQL_UPGRADE")>0 as have_mysql_upgrade; +--enable_query_log diff --git a/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result new file mode 100644 index 00000000000..09a9121d22c --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result @@ -0,0 +1,13 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +Master position is not changed +STOP SLAVE SQL_THREAD; +Master position has been changed +DROP DATABASE `mysqltest-1`; +DROP DATABASE `#mysql50#mysqltest-1`; diff --git a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test new file mode 100644 index 00000000000..bf5c6d2b921 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test @@ -0,0 +1,56 @@ +############################################################################# +# BUG#43579 mysql_upgrade tries to alter log tables on replicated database +# Master and slave should be upgraded separately. All statements executed by +# mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog +# options are added into mysql_upgrade. These options control whether sql +# statements are binlogged or not. +############################################################################# +--source include/master-slave.inc + +# Only run test if "mysql_upgrade" is found +--source include/have_mysql_upgrade.inc + +connection master; +--disable_warnings +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +--enable_warnings +sync_slave_with_master; + +connection master; +let $before_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +#--skip-write-binlog option disables binlog. +--exec $MYSQL_UPGRADE --skip-write-binlog --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 +sync_slave_with_master; + +connection master; +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (`SELECT '$before_position'='$after_position'`) +{ + echo Master position is not changed; +} + +#Some log events of the mysql_upgrade's will cause errors on slave. +connection slave; +STOP SLAVE SQL_THREAD; +source include/wait_for_slave_sql_to_stop.inc; + +connection master; +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +--exec $MYSQL_UPGRADE --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 + +connection master; +let $after_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (!`SELECT '$before_position'='$after_position'`) +{ + echo Master position has been changed; +} + +DROP DATABASE `mysqltest-1`; +connection slave; +DROP DATABASE `#mysql50#mysqltest-1`;