From 0af84363b1ab5ca6fced83c8dc24de6251cced3e Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 16 Apr 2012 12:36:21 +0200 Subject: [PATCH 01/32] Raise version number after cloning for the 5.5.24 build. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0f96ceb238d..6111f6d453f 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=24 +MYSQL_VERSION_PATCH=25 MYSQL_VERSION_EXTRA= From b61d6be9fdfa61b7ae8e8436cf1748fc126ec15f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 17 Apr 2012 13:25:41 +0300 Subject: [PATCH 02/32] Raise version number after cloning 5.1.63 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index ccc2ac26570..84295a15f4a 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.63], [], [mysql]) +AC_INIT([MySQL Server], [5.1.64], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From fe0400694171f0def529e35a77db128b835f5626 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Tue, 17 Apr 2012 16:54:02 +0530 Subject: [PATCH 03/32] Bug #12902967 CREATING SELF REFERENCING FK ON SAME INDEX UNHANDLED, CONFUSING ERROR The main confusion with the error message is that "it implies that your data dictionary may now be out of sync". This patch will remove the unwanted and the misleading error message by not doing an unnecessary operation in the error handling code. rb://980 approved by: Dmitry Lenev --- .../suite/innodb/r/innodb_bug12902967.result | 6 +++ .../suite/innodb/t/innodb_bug12902967.test | 42 +++++++++++++++ sql/sql_table.cc | 53 +++++++++++++++---- 3 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb_bug12902967.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug12902967.test diff --git a/mysql-test/suite/innodb/r/innodb_bug12902967.result b/mysql-test/suite/innodb/r/innodb_bug12902967.result new file mode 100644 index 00000000000..b20710f08fb --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug12902967.result @@ -0,0 +1,6 @@ +create table t1 (f1 integer primary key) engine innodb; +alter table t1 add constraint c1 foreign key (f1) references t1(f1); +ERROR HY000: Error on rename of '#sql-temporary' to './test/t1' (errno: 150) +InnoDB: which are not compatible with the new table definition. +InnoDB: has or is referenced in foreign key constraints +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb_bug12902967.test b/mysql-test/suite/innodb/t/innodb_bug12902967.test new file mode 100644 index 00000000000..87e648c2726 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug12902967.test @@ -0,0 +1,42 @@ +# Bug 12902967: Creating self referencing fk on same index unhandled, +# confusing error +# +# Creating a self referencing foreign key on the same +# column/index is an unhandled exception, it should throw a sensible +# error but instead implies that your data dictionary may now be out +# of sync: + +--source include/have_innodb.inc + +let error_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; +--remove_file $error_log +--source include/restart_mysqld.inc + +create table t1 (f1 integer primary key) engine innodb; + +# The below statement should produce error message in error log. +# This error message should mention problem with foreign keys +# rather than with data dictionary. +--replace_regex /'\.\/test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_ERROR_ON_RENAME +alter table t1 add constraint c1 foreign key (f1) references t1(f1); + +perl; + +$file = "$ENV{'error_log'}"; +open ( FILE, $file) || die "can't open file! ($file)\n"; +@lines = ; +close (FILE); +$count = 0; +foreach $line (reverse @lines) { + if ($line =~ "^InnoDB:") { + ++$count; + print "$line"; + if ($count == 2) { + break; + } + } +} +EOF + +drop table t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0f4bac47cab..c146079fdb3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -246,10 +246,17 @@ uint explain_filename(THD* thd, { part_name_len= tmp_p - part_name - 1; subpart_name= tmp_p + 3; + tmp_p+= 3; + } + else if ((tmp_p[1] == 'Q' || tmp_p[1] == 'q') && + (tmp_p[2] == 'L' || tmp_p[2] == 'l') && + tmp_p[3] == '-') + { + name_type= TEMP; + tmp_p+= 4; /* sql- prefix found */ } else res= 2; - tmp_p+= 3; break; case 'T': case 't': @@ -6718,21 +6725,47 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP); } else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, - new_alias, FN_FROM_IS_TMP) || - ((new_name != table_name || new_db != db) && // we also do rename - (need_copy_table != ALTER_TABLE_METADATA_ONLY || - mysql_rename_table(save_old_db_type, db, table_name, new_db, - new_alias, NO_FRM_RENAME)) && - Table_triggers_list::change_table_name(thd, db, alias, table_name, - new_db, new_alias))) + new_alias, FN_FROM_IS_TMP)) { /* Try to get everything back. */ - error=1; - (void) quick_rm_table(new_db_type,new_db,new_alias, 0); + error= 1; (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP); (void) mysql_rename_table(old_db_type, db, old_name, db, alias, FN_FROM_IS_TMP); } + else if (new_name != table_name || new_db != db) + { + if (need_copy_table == ALTER_TABLE_METADATA_ONLY && + mysql_rename_table(save_old_db_type, db, table_name, new_db, + new_alias, NO_FRM_RENAME)) + { + /* Try to get everything back. */ + error= 1; + (void) quick_rm_table(new_db_type, new_db, new_alias, 0); + (void) mysql_rename_table(old_db_type, db, old_name, db, alias, + FN_FROM_IS_TMP); + } + else if (Table_triggers_list::change_table_name(thd, db, alias, + table_name, new_db, + new_alias)) + { + /* Try to get everything back. */ + error= 1; + (void) quick_rm_table(new_db_type, new_db, new_alias, 0); + (void) mysql_rename_table(old_db_type, db, old_name, db, + alias, FN_FROM_IS_TMP); + /* + If we were performing "fast"/in-place ALTER TABLE we also need + to restore old name of table in storage engine as a separate + step, as the above rename affects .FRM only. + */ + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) + { + (void) mysql_rename_table(save_old_db_type, new_db, new_alias, + db, table_name, NO_FRM_RENAME); + } + } + } if (! error) (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP); From 75ff20a2b4311e9235fba71544c256481fe7f24b Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 18 Apr 2012 09:21:23 +0530 Subject: [PATCH 04/32] Bug #12902967 Creating self referencing fk on same index unhandled, confusing error. I have added the not_embedded.inc in the test file. --- mysql-test/suite/innodb/t/innodb_bug12902967.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/innodb/t/innodb_bug12902967.test b/mysql-test/suite/innodb/t/innodb_bug12902967.test index 87e648c2726..9101c8c705b 100644 --- a/mysql-test/suite/innodb/t/innodb_bug12902967.test +++ b/mysql-test/suite/innodb/t/innodb_bug12902967.test @@ -7,6 +7,7 @@ # of sync: --source include/have_innodb.inc +--source include/not_embedded.inc let error_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; --remove_file $error_log From 25f82f8a261963f633ccfdabce27dfc1e0309286 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Wed, 18 Apr 2012 11:25:01 +0530 Subject: [PATCH 05/32] Bug#12713907:STRANGE OPTIMIZE & WRONG RESULT UNDER ORDER BY COUNT(*) LIMIT. PROBLEM: With respect to problem in the bug description, we exhibit different behaviors for the two tables presented, because innodb statistics (rec_per_key in this case) are updated for the first table and not so for the second one. As a result the query plan gets changed in test_if_skip_sort_order to use 'index' scan. Hence the difference in the explain output. (NOTE: We can reproduce the problem with first table by reducing the number of tuples and changing the table structure) The varied output w.r.t the query on the second table is because of the result in the query plan change. When a query plan is changed to use 'index' scan, after the call to test_if_skip_sort_order, we set keyread to TRUE immedietly. If for some reason we drop this index scan for a filesort later on, we fetch only the keys not the entire tuple. As a result we would see junk values in the result set. Following is the code flow: Call test_if_skip_sort_order -Choose an index to give sorted output -If this is a covering index, set_keyread to TRUE -Set the scan to INDEX scan Call test_if_skip_sort_order second time -Index is not chosen (note that we do not pass the actual limit value second time. Hence we do not choose index scan second time which in itself is a bug fixed in 5.6 with WL#5558) -goto filesort Call filesort -Create quick range on a different index -Since keyread is set to TRUE, we fetch only the columns of the index -results in the required columns are not fetched FIX: Remove the call to set_keyread(TRUE) from test_if_skip_sort_order. The access function which is 'join_read_first' or 'join_read_last' calls set_keyread anyways. mysql-test/r/func_group_innodb.result: Added test result for Bug#12713907 mysql-test/t/func_group_innodb.test: Added test case for Bug#12713907 sql/sql_select.cc: Remove the call to set_keyread as we do it from access functions 'join_read_first' and 'join_read_last' --- mysql-test/r/func_group_innodb.result | 40 ++++++++++++++++++++++++ mysql-test/t/func_group_innodb.test | 44 +++++++++++++++++++++++++++ sql/sql_select.cc | 2 -- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_group_innodb.result b/mysql-test/r/func_group_innodb.result index 908e85c1652..e68242a8191 100644 --- a/mysql-test/r/func_group_innodb.result +++ b/mysql-test/r/func_group_innodb.result @@ -145,3 +145,43 @@ select count(*), min(7), max(7) from t2m, t1i; count(*) min(7) max(7) 0 NULL NULL drop table t1m, t1i, t2m, t2i; +# +# Bug#12713907: STRANGE OPTIMIZE & WRONG RESULT UNDER ORDER BY +# COUNT(*) LIMIT. +# +CREATE TABLE t1 ( +id BIGINT(20) , +member_id_to INT(11) , +r_date DATE , +PRIMARY KEY (id,r_date), +KEY r_date_idx (r_date), +KEY t1_idx01 (member_id_to) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(107924526,518491,'2011-05-01'), +(107924527,518491,'2011-05-01'), +(107924528,518491,'2011-05-01'), +(107924529,518491,'2011-05-01'), +(107924530,518491,'2011-05-01'), +(107924531,518491,'2011-05-01'), +(107924532,518491,'2011-05-01'), +(107924534,518491,'2011-06-21'), +(107924535,518491,'2011-06-21'), +(107924536,518491,'2011-06-21'), +(107924537,518491,'2011-06-21'), +(107924538,518491,'2011-06-21'), +(107924542,1601319,'2011-06-21'), +(107924543,1601319,'2011-06-21'), +(107924544,1601319,'2011-06-21'), +(107924545,1601319,'2011-06-21'), +(107924546,1601319,'2011-06-21'), +(107924547,1601319,'2011-06-21'), +(107924548,1601319,'2011-06-21'), +(107924549,1601319,'2011-06-21'), +(107924550,1601319,'2011-06-21'); +SELECT member_id_to, COUNT(*) FROM t1 WHERE r_date = +'2011-06-21' GROUP BY member_id_to ORDER BY 2 LIMIT 1; +member_id_to COUNT(*) +518491 5 +DROP TABLE t1; +# End of test BUG#12713907 diff --git a/mysql-test/t/func_group_innodb.test b/mysql-test/t/func_group_innodb.test index 1bdfd8f54bb..58f365bb244 100644 --- a/mysql-test/t/func_group_innodb.test +++ b/mysql-test/t/func_group_innodb.test @@ -83,3 +83,47 @@ explain select count(*), min(7), max(7) from t2m, t1i; select count(*), min(7), max(7) from t2m, t1i; drop table t1m, t1i, t2m, t2i; + +--echo # +--echo # Bug#12713907: STRANGE OPTIMIZE & WRONG RESULT UNDER ORDER BY +--echo # COUNT(*) LIMIT. +--echo # + +CREATE TABLE t1 ( +id BIGINT(20) , +member_id_to INT(11) , +r_date DATE , +PRIMARY KEY (id,r_date), +KEY r_date_idx (r_date), +KEY t1_idx01 (member_id_to) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES +(107924526,518491,'2011-05-01'), +(107924527,518491,'2011-05-01'), +(107924528,518491,'2011-05-01'), +(107924529,518491,'2011-05-01'), +(107924530,518491,'2011-05-01'), +(107924531,518491,'2011-05-01'), +(107924532,518491,'2011-05-01'), +(107924534,518491,'2011-06-21'), +(107924535,518491,'2011-06-21'), +(107924536,518491,'2011-06-21'), +(107924537,518491,'2011-06-21'), +(107924538,518491,'2011-06-21'), +(107924542,1601319,'2011-06-21'), +(107924543,1601319,'2011-06-21'), +(107924544,1601319,'2011-06-21'), +(107924545,1601319,'2011-06-21'), +(107924546,1601319,'2011-06-21'), +(107924547,1601319,'2011-06-21'), +(107924548,1601319,'2011-06-21'), +(107924549,1601319,'2011-06-21'), +(107924550,1601319,'2011-06-21'); + +SELECT member_id_to, COUNT(*) FROM t1 WHERE r_date = + '2011-06-21' GROUP BY member_id_to ORDER BY 2 LIMIT 1; + +DROP TABLE t1; + +--echo # End of test BUG#12713907 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5f1efabfc97..1c5f4f5a648 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13820,8 +13820,6 @@ check_reverse_order: join_read_first:join_read_last; tab->type=JT_NEXT; // Read with index_first(), index_next() - if (table->covering_keys.is_set(best_key)) - table->set_keyread(TRUE); table->file->ha_index_or_rnd_end(); if (tab->join->select_options & SELECT_DESCRIBE) { From 448c3d627542c835ac7ea1851e8e019596e377fd Mon Sep 17 00:00:00 2001 From: Nuno Carvalho Date: Wed, 18 Apr 2012 10:08:01 +0100 Subject: [PATCH 06/32] WL#6236: Allow SHOW MASTER LOGS and SHOW BINARY LOGS with REPLICATION CLIENT Currently SHOW MASTER LOGS and SHOW BINARY LOGS require the SUPER privilege. Monitoring tools (such as MEM) often want to check this output - for instance MEM generates the SUM of the sizes of the logs reported here, and puts that in the Replication overview within the MEM Dashboard. However, because of the SUPER requirement, these tools often have an account that holds open the connection whilst monitoring, and can lock out administrators when the server gets overloaded and reaches max_connections - there is already another SUPER privileged account connected, the "monitor". As SHOW MASTER STATUS, and all other replication related statements, return with either REPLICATION CLIENT or SUPER privileges, this worklog is to make SHOW MASTER LOGS and SHOW BINARY LOGS be consistent with this as well, and allow both of these commands with either SUPER or REPLICATION CLIENT. This allows monitoring tools to not require a SUPER privilege any more, so is safer in overloaded situations, as well as being more secure, as lighter privileges can be given to users of such tools or scripts. --- mysql-test/suite/binlog/r/binlog_grant.result | 4 ++++ mysql-test/suite/binlog/t/binlog_grant.test | 19 +++++++++++++++++++ sql/sql_parse.cc | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/binlog/r/binlog_grant.result b/mysql-test/suite/binlog/r/binlog_grant.result index 21ebb891103..38442349d3b 100644 --- a/mysql-test/suite/binlog/r/binlog_grant.result +++ b/mysql-test/suite/binlog/r/binlog_grant.result @@ -26,3 +26,7 @@ ERROR 42000: Access denied; you need the SUPER privilege for this operation **** Clean up **** set global binlog_format = @saved_binlog_format; drop user mysqltest_1@localhost; +GRANT REPLICATION CLIENT ON *.* TO 'mysqltest_1'@'localhost'; +SHOW MASTER LOGS; +SHOW BINARY LOGS; +DROP USER 'mysqltest_1'@'localhost'; diff --git a/mysql-test/suite/binlog/t/binlog_grant.test b/mysql-test/suite/binlog/t/binlog_grant.test index d36dcce4cc3..bbf57b075af 100644 --- a/mysql-test/suite/binlog/t/binlog_grant.test +++ b/mysql-test/suite/binlog/t/binlog_grant.test @@ -58,3 +58,22 @@ disconnect root; connection default; set global binlog_format = @saved_binlog_format; drop user mysqltest_1@localhost; + + +# Testing if REPLICATION CLIENT privilege is enough to execute +# SHOW MASTER LOGS and SHOW BINARY. +GRANT REPLICATION CLIENT ON *.* TO 'mysqltest_1'@'localhost'; +--connect(rpl,localhost,mysqltest_1,,) + +--connection rpl +# We are only interested if the following commands succeed and not on +# their output. +--disable_result_log +SHOW MASTER LOGS; +SHOW BINARY LOGS; +--enable_result_log + +# clean up +--disconnect rpl +connection default; +DROP USER 'mysqltest_1'@'localhost'; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0f190809ab9..14b778328d2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3057,7 +3057,7 @@ end_with_restore_list: goto error; #else { - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; res = show_binlogs(thd); break; From b73da023bfc173b404f5298d6b8b36cc8cfc493d Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 18 Apr 2012 15:16:11 +0530 Subject: [PATCH 07/32] Bug #12902967 Creating self referencing fk on same index unhandled, confusing error. Updated the test script to work properly on windows platform. --- mysql-test/suite/innodb/t/innodb_bug12902967.test | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/t/innodb_bug12902967.test b/mysql-test/suite/innodb/t/innodb_bug12902967.test index 9101c8c705b..7bc5727a7a6 100644 --- a/mysql-test/suite/innodb/t/innodb_bug12902967.test +++ b/mysql-test/suite/innodb/t/innodb_bug12902967.test @@ -10,7 +10,6 @@ --source include/not_embedded.inc let error_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; ---remove_file $error_log --source include/restart_mysqld.inc create table t1 (f1 integer primary key) engine innodb; @@ -21,7 +20,7 @@ create table t1 (f1 integer primary key) engine innodb; --replace_regex /'\.\/test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ --error ER_ERROR_ON_RENAME alter table t1 add constraint c1 foreign key (f1) references t1(f1); - +--source include/restart_mysqld.inc perl; $file = "$ENV{'error_log'}"; From 11b2cf4f03b7c4b84c26d3c95cdf6f8fa6322349 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 18 Apr 2012 13:14:05 +0200 Subject: [PATCH 08/32] Backport 5.5=>5.1 Patch for Bug#13805127: Stored program cache produces wrong result in same THD. --- mysql-test/r/ps.result | 103 ++++++++++++++++++++++++ mysql-test/r/sp.result | 38 +++++++++ mysql-test/t/ps.test | 90 +++++++++++++++++++++ mysql-test/t/sp.test | 37 +++++++++ sql/mem_root_array.h | 175 +++++++++++++++++++++++++++++++++++++++++ sql/sql_lex.cc | 22 ++++++ sql/sql_lex.h | 16 +++- sql/sql_prepare.cc | 8 ++ 8 files changed, 487 insertions(+), 2 deletions(-) create mode 100644 sql/mem_root_array.h diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 84c64a3905a..60370e4b708 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -3040,3 +3040,106 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; DROP TABLE t1; End of 5.1 tests. + +# Bug#13805127: Stored program cache produces wrong result in same THD + +PREPARE s1 FROM +" +SELECT c1, t2.c2, count(c3) +FROM + ( + SELECT 3 as c2 FROM dual WHERE @x = 1 + UNION + SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2 +"; + +SET @x = 1; +SELECT c1, t2.c2, count(c3) +FROM +( +SELECT 3 as c2 FROM dual WHERE @x = 1 +UNION +SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 +) AS t1, +( +SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual +UNION +SELECT '2012-03-01 02:00:00', 3, 2 FROM dual +UNION +SELECT '2012-03-01 01:00:00', 2, 1 FROM dual +) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 + +EXECUTE s1; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 + +SET @x = 2; +SELECT c1, t2.c2, count(c3) +FROM +( +SELECT 3 as c2 FROM dual WHERE @x = 1 +UNION +SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 +) AS t1, +( +SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual +UNION +SELECT '2012-03-01 02:00:00', 3, 2 FROM dual +UNION +SELECT '2012-03-01 01:00:00', 2, 1 FROM dual +) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 + +EXECUTE s1; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 + +SET @x = 1; +SELECT c1, t2.c2, count(c3) +FROM +( +SELECT 3 as c2 FROM dual WHERE @x = 1 +UNION +SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 +) AS t1, +( +SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual +UNION +SELECT '2012-03-01 02:00:00', 3, 2 FROM dual +UNION +SELECT '2012-03-01 01:00:00', 2, 1 FROM dual +) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 + +EXECUTE s1; +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 +DEALLOCATE PREPARE s1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 11d6ff02756..0d0d76e609b 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -7110,3 +7110,41 @@ DROP FUNCTION f1; # ------------------------------------------------------------------ # -- End of 5.1 tests # ------------------------------------------------------------------ + +# Bug#13805127: Stored program cache produces wrong result in same THD + +CREATE PROCEDURE p1(x INT UNSIGNED) +BEGIN +SELECT c1, t2.c2, count(c3) +FROM +( +SELECT 3 as c2 FROM dual WHERE x = 1 +UNION +SELECT 2 FROM dual WHERE x = 1 OR x = 2 +) AS t1, +( +SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual +UNION +SELECT '2012-03-01 02:00:00', 3, 2 FROM dual +UNION +SELECT '2012-03-01 01:00:00', 2, 1 FROM dual +) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2 +; +END| + +CALL p1(1); +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 +CALL p1(2); +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +CALL p1(1); +c1 c2 count(c3) +2012-03-01 01:00:00 2 1 +2012-03-01 01:00:00 3 1 +2012-03-01 02:00:00 3 1 +DROP PROCEDURE p1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 9b3f3e750e1..88bfe1dd2be 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -3102,3 +3102,93 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1; --echo End of 5.1 tests. + +--echo +--echo # Bug#13805127: Stored program cache produces wrong result in same THD +--echo + +PREPARE s1 FROM +" +SELECT c1, t2.c2, count(c3) +FROM + ( + SELECT 3 as c2 FROM dual WHERE @x = 1 + UNION + SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2 +"; + +--echo +SET @x = 1; +SELECT c1, t2.c2, count(c3) +FROM + ( + SELECT 3 as c2 FROM dual WHERE @x = 1 + UNION + SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +--echo +EXECUTE s1; + +--echo +SET @x = 2; +SELECT c1, t2.c2, count(c3) +FROM + ( + SELECT 3 as c2 FROM dual WHERE @x = 1 + UNION + SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +--echo +EXECUTE s1; + +--echo +SET @x = 1; +SELECT c1, t2.c2, count(c3) +FROM + ( + SELECT 3 as c2 FROM dual WHERE @x = 1 + UNION + SELECT 2 FROM dual WHERE @x = 1 OR @x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 +WHERE t2.c2 = t1.c2 +GROUP BY c1, c2; +--echo +EXECUTE s1; + +DEALLOCATE PREPARE s1; + diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index ae4e1dd588e..75d290f7c8b 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8429,3 +8429,40 @@ DROP FUNCTION f1; --echo # ------------------------------------------------------------------ --echo # -- End of 5.1 tests --echo # ------------------------------------------------------------------ + +--echo +--echo # Bug#13805127: Stored program cache produces wrong result in same THD +--echo + +delimiter |; + +CREATE PROCEDURE p1(x INT UNSIGNED) +BEGIN + SELECT c1, t2.c2, count(c3) + FROM + ( + SELECT 3 as c2 FROM dual WHERE x = 1 + UNION + SELECT 2 FROM dual WHERE x = 1 OR x = 2 + ) AS t1, + ( + SELECT '2012-03-01 01:00:00' AS c1, 3 as c2, 1 as c3 FROM dual + UNION + SELECT '2012-03-01 02:00:00', 3, 2 FROM dual + UNION + SELECT '2012-03-01 01:00:00', 2, 1 FROM dual + ) AS t2 + WHERE t2.c2 = t1.c2 + GROUP BY c1, c2 + ; +END| + +delimiter ;| + +--echo +CALL p1(1); +CALL p1(2); +CALL p1(1); + +DROP PROCEDURE p1; + diff --git a/sql/mem_root_array.h b/sql/mem_root_array.h new file mode 100644 index 00000000000..5ce4dcb584d --- /dev/null +++ b/sql/mem_root_array.h @@ -0,0 +1,175 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef MEM_ROOT_ARRAY_INCLUDED +#define MEM_ROOT_ARRAY_INCLUDED + +#include + +/** + A typesafe replacement for DYNAMIC_ARRAY. + We use MEM_ROOT for allocating storage, rather than the C++ heap. + The interface is chosen to be similar to std::vector. + + @remark + Unlike DYNAMIC_ARRAY, elements are properly copied + (rather than memcpy()d) if the underlying array needs to be expanded. + + @remark + Depending on has_trivial_destructor, we destroy objects which are + removed from the array (including when the array object itself is destroyed). + + @remark + Note that MEM_ROOT has no facility for reusing free space, + so don't use this if multiple re-expansions are likely to happen. + + @param Element_type The type of the elements of the container. + Elements must be copyable. + @param has_trivial_destructor If true, we don't destroy elements. + We could have used type traits to determine this. + __has_trivial_destructor is supported by some (but not all) + compilers we use. +*/ +template +class Mem_root_array +{ +public: + Mem_root_array(MEM_ROOT *root) + : m_root(root), m_array(NULL), m_size(0), m_capacity(0) + { + DBUG_ASSERT(m_root != NULL); + } + + ~Mem_root_array() + { + clear(); + } + + Element_type &at(size_t n) + { + DBUG_ASSERT(n < size()); + return m_array[n]; + } + + const Element_type &at(size_t n) const + { + DBUG_ASSERT(n < size()); + return m_array[n]; + } + + // Returns a pointer to the first element in the array. + Element_type *begin() { return &m_array[0]; } + + // Returns a pointer to the past-the-end element in the array. + Element_type *end() { return &m_array[size()]; } + + // Erases all of the elements. + void clear() + { + if (!empty()) + chop(0); + } + + /* + Chops the tail off the array, erasing all tail elements. + @param pos Index of first element to erase. + */ + void chop(const size_t pos) + { + DBUG_ASSERT(pos < m_size); + if (!has_trivial_destructor) + { + for (size_t ix= pos; ix < m_size; ++ix) + { + Element_type *p= &m_array[ix]; + p->~Element_type(); // Destroy discarded element. + } + } + m_size= pos; + } + + /* + Reserves space for array elements. + Copies over existing elements, in case we are re-expanding the array. + + @param n number of elements. + @retval true if out-of-memory, false otherwise. + */ + bool reserve(size_t n) + { + if (n <= m_capacity) + return false; + + void *mem= alloc_root(m_root, n * element_size()); + if (!mem) + return true; + Element_type *array= static_cast(mem); + + // Copy all the existing elements into the new array. + for (size_t ix= 0; ix < m_size; ++ix) + { + Element_type *new_p= &array[ix]; + Element_type *old_p= &m_array[ix]; + new (new_p) Element_type(*old_p); // Copy into new location. + if (!has_trivial_destructor) + old_p->~Element_type(); // Destroy the old element. + } + + // Forget the old array. + m_array= array; + m_capacity= n; + return false; + } + + /* + Adds a new element at the end of the array, after its current last + element. The content of this new element is initialized to a copy of + the input argument. + + @param element Object to copy. + @retval true if out-of-memory, false otherwise. + */ + bool push_back(const Element_type &element) + { + const size_t min_capacity= 20; + const size_t expansion_factor= 2; + if (0 == m_capacity && reserve(min_capacity)) + return true; + if (m_size == m_capacity && reserve(m_capacity * expansion_factor)) + return true; + Element_type *p= &m_array[m_size++]; + new (p) Element_type(element); + return false; + } + + size_t capacity() const { return m_capacity; } + size_t element_size() const { return sizeof(Element_type); } + bool empty() const { return size() == 0; } + size_t size() const { return m_size; } + +private: + MEM_ROOT *const m_root; + Element_type *m_array; + size_t m_size; + size_t m_capacity; + + // Not (yet) implemented. + Mem_root_array(const Mem_root_array&); + Mem_root_array &operator=(const Mem_root_array&); +}; + + +#endif // MEM_ROOT_ARRAY_INCLUDED diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4a0553ad59b..fd9367b99f2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -305,6 +305,8 @@ void lex_start(THD *thd) lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; lex->select_lex.init_order(); lex->select_lex.group_list.empty(); + if (lex->select_lex.group_list_ptrs) + lex->select_lex.group_list_ptrs->clear(); lex->describe= 0; lex->subqueries= FALSE; lex->context_analysis_only= 0; @@ -1632,6 +1634,8 @@ void st_select_lex::init_select() { st_select_lex_node::init_select(); group_list.empty(); + if (group_list_ptrs) + group_list_ptrs->clear(); type= db= 0; having= 0; table_join_options= 0; @@ -2901,6 +2905,8 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl) The passed WHERE and HAVING are to be saved for the future executions. This function saves it, and returns a copy which can be thrashed during this execution of the statement. By saving/thrashing here we mean only + We also save the chain of ORDER::next in group_list, in case + the list is modified by remove_const(). AND/OR trees. The function also calls fix_prepare_info_in_table_list that saves all ON expressions. @@ -2912,6 +2918,19 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, if (!thd->stmt_arena->is_conventional() && first_execution) { first_execution= 0; + if (group_list.first) + { + if (!group_list_ptrs) + { + void *mem= thd->stmt_arena->alloc(sizeof(Group_list_ptrs)); + group_list_ptrs= new (mem) Group_list_ptrs(thd->stmt_arena->mem_root); + } + group_list_ptrs->reserve(group_list.elements); + for (ORDER *order= group_list.first; order; order= order->next) + { + group_list_ptrs->push_back(order); + } + } if (*conds) { prep_where= *conds; @@ -3016,3 +3035,6 @@ bool st_lex::is_partition_management() const alter_info.flags == ALTER_REORGANIZE_PARTITION)); } +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +template class Mem_root_array; +#endif diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 035fa1fde91..d512190eecc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -40,6 +40,7 @@ class Event_parse_data; */ #include "set_var.h" +#include "mem_root_array.h" #ifdef MYSQL_YACC #define LEX_YYSTYPE void * @@ -183,6 +184,7 @@ enum enum_drop_mode }; typedef List List_item; +typedef Mem_root_array Group_list_ptrs; /* SERVERS CACHE CHANGES */ typedef struct st_lex_server_options @@ -590,7 +592,16 @@ public: enum olap_type olap; /* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */ SQL_I_List table_list; - SQL_I_List group_list; /* GROUP BY clause. */ + + /* + GROUP BY clause. + This list may be mutated during optimization (by remove_const()), + so for prepared statements, we keep a copy of the ORDER.next pointers in + group_list_ptrs, and re-establish the original list before each execution. + */ + SQL_I_List group_list; + Group_list_ptrs *group_list_ptrs; + List item_list; /* list of fields & expressions */ List interval_list; bool is_item_list_lookup; @@ -779,7 +790,8 @@ public: bool test_limit(); friend void lex_start(THD *thd); - st_select_lex() : n_sum_items(0), n_child_sum_items(0) {} + st_select_lex() : group_list_ptrs(NULL), n_sum_items(0), n_child_sum_items(0) + {} void make_empty_select() { init_query(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 98379dba9ba..27e70aaf843 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2361,6 +2361,14 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) DBUG_ASSERT(sl->join == 0); ORDER *order; /* Fix GROUP list */ + if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0) + { + for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix) + { + order= sl->group_list_ptrs->at(ix); + order->next= sl->group_list_ptrs->at(ix+1); + } + } for (order= sl->group_list.first; order; order= order->next) order->item= &order->item_ptr; /* Fix ORDER list */ From 892106db9219f2714a65bd0d07da262c5aaa8fca Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 18 Apr 2012 14:13:13 +0200 Subject: [PATCH 09/32] new header file must be listed in Makefile.am --- sql/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/Makefile.am b/sql/Makefile.am index f8ba25377cd..2336faf4e31 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -71,6 +71,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ + mem_root_array.h \ sql_array.h sql_cursor.h events.h scheduler.h \ event_db_repository.h event_queue.h \ sql_plugin.h authors.h event_parse_data.h \ From bf4161adae1a0b103d5424f2fe3ec8c167311997 Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Thu, 19 Apr 2012 14:57:34 +0530 Subject: [PATCH 10/32] BUG#12427262 : 60961: SHOW TABLES VERY SLOW WHEN NOT IN SYSTEM DISK CACHE Reason: This is a regression happened because of changes done in code refactoring in 5.1 from 5.0. Issue: While doing "Show tables" lex->verbose was being checked to avoid opening FRM files to get table type. In case of "Show full table", lex->verbose is true to indicate table type is required. In 5.0, this check was present which got missing in >=5.5. Fix: Added the required check to avoid opening FRM files unnecessarily in case of "Show tables". --- sql/sql_show.cc | 68 +++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ab3217dbe48..1b0f94ce18e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3198,39 +3198,44 @@ end: static int fill_schema_table_names(THD *thd, TABLE *table, LEX_STRING *db_name, LEX_STRING *table_name, - bool with_i_schema) + bool with_i_schema, + bool need_table_type) { - if (with_i_schema) + /* Avoid opening FRM files if table type is not needed. */ + if (need_table_type) { - table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), - system_charset_info); - } - else - { - enum legacy_db_type not_used; - char path[FN_REFLEN + 1]; - (void) build_table_filename(path, sizeof(path) - 1, db_name->str, - table_name->str, reg_ext, 0); - switch (mysql_frm_type(thd, path, ¬_used)) { - case FRMTYPE_ERROR: - table->field[3]->store(STRING_WITH_LEN("ERROR"), - system_charset_info); - break; - case FRMTYPE_TABLE: - table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), - system_charset_info); - break; - case FRMTYPE_VIEW: - table->field[3]->store(STRING_WITH_LEN("VIEW"), - system_charset_info); - break; - default: - DBUG_ASSERT(0); - } - if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + if (with_i_schema) { - thd->clear_error(); - return 0; + table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), + system_charset_info); + } + else + { + enum legacy_db_type not_used; + char path[FN_REFLEN + 1]; + (void) build_table_filename(path, sizeof(path) - 1, db_name->str, + table_name->str, reg_ext, 0); + switch (mysql_frm_type(thd, path, ¬_used)) { + case FRMTYPE_ERROR: + table->field[3]->store(STRING_WITH_LEN("ERROR"), + system_charset_info); + break; + case FRMTYPE_TABLE: + table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), + system_charset_info); + break; + case FRMTYPE_VIEW: + table->field[3]->store(STRING_WITH_LEN("VIEW"), + system_charset_info); + break; + default: + DBUG_ASSERT(0); + } + if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) + { + thd->clear_error(); + return 0; + } } } if (schema_table_store_record(thd, table)) @@ -3551,7 +3556,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (schema_table_idx == SCH_TABLE_NAMES) { if (fill_schema_table_names(thd, tables->table, db_name, - table_name, with_i_schema)) + table_name, with_i_schema, + lex->verbose)) continue; } else From 49e484c8cd2e362e843bbd5d756422cc7e2686d3 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 20 Apr 2012 19:41:20 +0300 Subject: [PATCH 11/32] BUG#11754117 incorrect logging of INSERT into auto-increment BUG#11761686 insert_id event is not filtered. Two issues are covered. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe by autoincrement logging design. The case is specific to MyISAM engine because Innodb does not allow such table definition. However no warnings and row-format logging in the MIXED mode was done, and that is fixed. Int-, Rand-, User-var log-events were not filtered along with their parent query that made possible them to screw up execution context of the following query. Fixed with deferring their execution until the parent query. ****** Bug#11754117 Post review fixes. mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result: a new result file is added. mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result: results updated. mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test: regression test for BUG#11754117-45670 is added. mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test: regression test for filtering issue of BUG#11754117 - 45670 is added. sql/log_event.cc: Logics are added for deferring and executing events associated with the Query event. sql/log_event.h: Interface to deferred events batch execution is added. sql/rpl_rli.cc: initialization for new RLI members is added. sql/rpl_rli.h: New members to RLI are added to facilitate deferred events gathering and execution control; two general character RLI cleanup methods are constructed. sql/rpl_utility.cc: Deferred_log_events methods are difined. sql/rpl_utility.h: A new class Deferred_log_events is defined to implement IRU events gathering, execution and cleanup. sql/slave.cc: Necessary changes to initialize `rli->deferred_events' and prevent deferred event deletion in the main read-exec branch. sql/sql_base.cc: A new safe-check function for multi-part pk with auto-increment is defined and deployed in lock_tables(). sql/sql_class.cc: Initialization for a new member and replication cleanups are added to THD class. sql/sql_class.h: THD class receives a new member to hold a specific execution context for slave applier. sql/sql_parse.cc: Execution of the deferred event in started prior to its parent query. --- .../rpl/r/rpl_auto_increment_bug45679.result | 36 +++++++++++ .../rpl/r/rpl_filter_tables_not_exist.result | 21 +++++++ .../rpl/t/rpl_auto_increment_bug45679.test | 62 +++++++++++++++++++ .../rpl/t/rpl_filter_tables_not_exist.test | 60 ++++++++++++++++++ sql/log_event.cc | 36 ++++++++++- sql/log_event.h | 10 +++ sql/rpl_rli.cc | 4 +- sql/rpl_rli.h | 35 +++++++++++ sql/rpl_utility.cc | 61 ++++++++++++++++++ sql/rpl_utility.h | 18 ++++++ sql/slave.cc | 9 ++- sql/sql_base.cc | 34 ++++++++++ sql/sql_class.cc | 8 ++- sql/sql_class.h | 2 + sql/sql_parse.cc | 5 ++ 15 files changed, 397 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result create mode 100644 mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result new file mode 100644 index 00000000000..75f4e661dc1 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result @@ -0,0 +1,36 @@ +include/master-slave.inc +[connection master] +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'); +create table tm (b int auto_increment, a int, primary key (a,b)) engine= myisam; +create table ti (b int auto_increment, a int, primary key (a,b)) engine= innodb; +ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key +create table ti (b int auto_increment, a int, primary key (b,a)) engine= innodb; +set @@binlog_format=statement; +*** autoincrement field is not the first in PK warning must be there: *** +insert into tm set b=null, a=1; +Warnings: +Note 1592 Statement may not be safe to log in statement format. +show warnings; +Level Code Message +Note 1592 Statement may not be safe to log in statement format. +*** no warning when autoincrement is the first in PK +insert into ti set b=null, a=1; +show warnings; +Level Code Message +create function multi_part_pk_with_autoinc (arg int) +returns int +begin +insert into tm set b=null, a=arg; +return arg; +end// +select multi_part_pk_with_autoinc (3); +multi_part_pk_with_autoinc (3) +3 +*** autoincrement field is not the first in PK warning must be there: *** +show warnings; +Level Code Message +set @@binlog_format=mixed; +insert into tm set b=null, a=2; +drop table tm, ti; +drop function multi_part_pk_with_autoinc; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result index c88dcee9dbc..f0dc97b71f2 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result +++ b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result @@ -114,4 +114,25 @@ id c 3 3 [on master] drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +CREATE TABLE test.t1 (a INT); +INSERT INTO test.t1 VALUES(1); +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW +INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c); +SET INSERT_ID=2; +SET @c=2; +SET @@rand_seed1=10000000, @@rand_seed2=1000000; +INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); +Warnings: +Note 1592 Statement may not be safe to log in statement format. +SELECT b into @b FROM test.t5; +UPDATE test.t1 SET a=2; +SELECT a AS 'ONE' into @a FROM test.t_slave; +SELECT c AS 'NULL' into @c FROM test.t_slave; +SELECT b into @b FROM test.t_slave; +drop table test.t5; +drop table test.t1; +drop table test.t_slave; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test new file mode 100644 index 00000000000..6996e1c73c7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test @@ -0,0 +1,62 @@ +# Test of auto-increment. +# +# BUG#11754117-45670 +# Multipart primary key with the autoincrement part not first in it +# is replication unsafe. +# + +source include/master-slave.inc; +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; + +call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.'); + +--connection master +create table tm (b int auto_increment, a int, primary key (a,b)) engine= myisam; +--error ER_WRONG_AUTO_KEY +create table ti (b int auto_increment, a int, primary key (a,b)) engine= innodb; +create table ti (b int auto_increment, a int, primary key (b,a)) engine= innodb; + +set @@binlog_format=statement; +--echo *** autoincrement field is not the first in PK warning must be there: *** +insert into tm set b=null, a=1; +show warnings; +--echo *** no warning when autoincrement is the first in PK +insert into ti set b=null, a=1; +show warnings; + +delimiter //; +create function multi_part_pk_with_autoinc (arg int) +returns int +begin + insert into tm set b=null, a=arg; + return arg; +end// +delimiter ;// + +select multi_part_pk_with_autoinc (3); +--echo *** autoincrement field is not the first in PK warning must be there: *** +show warnings; + +set @@binlog_format=mixed; +insert into tm set b=null, a=2; + +sync_slave_with_master; + +if (`select count(*) <> 3 from tm`) +{ + --echo Wrong result from SELECT on the slave side. + select * from tm; + --die +} + +# cleanup + +--connection master + +drop table tm, ti; +drop function multi_part_pk_with_autoinc; + +sync_slave_with_master; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test index 13c66f9f64b..b62a6e96437 100644 --- a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test @@ -206,4 +206,64 @@ SELECT * FROM t3; connection master; echo [on master]; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; + +--sync_slave_with_master + +# +# BUG#11754117 - 45670: INTVAR_EVENTS FOR FILTERED-OUT QUERY_LOG_EVENTS ARE EXECUTED +# Int-, Rand- and User- var events accompaning a filtered out Query-log-event should +# be filtered as well. +# +connection master; +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); # ignored on slave +CREATE TABLE test.t1 (a INT); # accepted on slave +INSERT INTO test.t1 VALUES(1); + +--sync_slave_with_master +call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT"); +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); +CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW + INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c); + +connection master; +SET INSERT_ID=2; +SET @c=2; +SET @@rand_seed1=10000000, @@rand_seed2=1000000; +INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); # to be ignored +SELECT b into @b FROM test.t5; +--let $b_master=`select @b` +UPDATE test.t1 SET a=2; # to run trigger on slave + +--sync_slave_with_master + +# The proof: +SELECT a AS 'ONE' into @a FROM test.t_slave; +SELECT c AS 'NULL' into @c FROM test.t_slave; + +let $count= 1; +let $table= test.t_slave; +source include/wait_until_rows_count.inc; + +if (`SELECT @a != 2 and @c != NULL`) +{ + SELECT * FROM test.t_slave; + --die Intvar or user var from replication events unexpetedly escaped out to screw a following query applying context. +} + +SELECT b into @b FROM test.t_slave; +--let $b_slave=`select @b` + +if (`SELECT $b_slave = $b_master`) +{ + --echo Might be pure coincidence of two randoms from master and slave table. Don not panic yet. +} + +# cleanup BUG#11754117 +connection master; +drop table test.t5; +drop table test.t1; + +--sync_slave_with_master +drop table test.t_slave; + --source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 427f27650dd..8606964113c 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5257,11 +5257,12 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) #endif +#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT) + /* Intvar_log_event::do_apply_event() */ -#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT) int Intvar_log_event::do_apply_event(Relay_log_info const *rli) { /* @@ -5270,6 +5271,9 @@ int Intvar_log_event::do_apply_event(Relay_log_info const *rli) */ const_cast(rli)->set_flag(Relay_log_info::IN_STMT); + if (rli->deferred_events_collecting) + return rli->deferred_events->add(this); + switch (type) { case LAST_INSERT_ID_EVENT: thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1; @@ -5375,6 +5379,9 @@ int Rand_log_event::do_apply_event(Relay_log_info const *rli) */ const_cast(rli)->set_flag(Relay_log_info::IN_STMT); + if (rli->deferred_events_collecting) + return rli->deferred_events->add(this); + thd->rand.seed1= (ulong) seed1; thd->rand.seed2= (ulong) seed2; return 0; @@ -5401,6 +5408,29 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli) return continue_group(rli); } +/** + Exec deferred Int-, Rand- and User- var events prefixing + a Query-log-event event. + + @param thd THD handle + + @return false on success, true if a failure in an event applying occurred. +*/ +bool slave_execute_deferred_events(THD *thd) +{ + bool res= false; + Relay_log_info *rli= thd->rli_slave; + + DBUG_ASSERT(rli && (!rli->deferred_events_collecting || rli->deferred_events)); + + if (!rli->deferred_events_collecting || rli->deferred_events->is_empty()) + return res; + + res= rli->deferred_events->execute(rli); + + return res; +} + #endif /* !MYSQL_CLIENT */ @@ -5785,6 +5815,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) { Item *it= 0; CHARSET_INFO *charset; + + if (rli->deferred_events_collecting) + return rli->deferred_events->add(this); + if (!(charset= get_charset(charset_number, MYF(MY_WME)))) return 1; LEX_STRING user_var_name; diff --git a/sql/log_event.h b/sql/log_event.h index 7c707c29278..4c80148458c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3961,6 +3961,16 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE); } +#ifndef MYSQL_CLIENT +/** + The function is called by slave applier in case there are + active table filtering rules to force gathering events associated + with Query-log-event into an array to execute + them once the fate of the Query is determined for execution. +*/ +bool slave_execute_deferred_events(THD *thd); +#endif + /** @} (end of group Replication) */ diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 6fe4cbd4ea6..904b5533f3b 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -45,7 +45,9 @@ Relay_log_info::Relay_log_info() inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0), retried_trans(0), tables_to_lock(0), tables_to_lock_count(0), - last_event_start_time(0), m_flags(0) + last_event_start_time(0), + deferred_events(NULL), + m_flags(0) { DBUG_ENTER("Relay_log_info::Relay_log_info"); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index f49be72db46..959105b16e0 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -369,6 +369,41 @@ public: */ time_t last_event_start_time; + /* + A container to hold on Intvar-, Rand-, Uservar- log-events in case + the slave is configured with table filtering rules. + The withhold events are executed when their parent Query destiny is + determined for execution as well. + */ + Deferred_log_events *deferred_events; + + /* + State of the container: true stands for IRU events gathering, + false does for execution, either deferred or direct. + */ + bool deferred_events_collecting; + + /* + Returns true if the argument event resides in the containter; + more specifically, the checking is done against the last added event. + */ + bool is_deferred_event(Log_event * ev) + { + return deferred_events_collecting ? deferred_events->is_last(ev) : false; + }; + /* The general cleanup that slave applier may need at the end of query. */ + inline void cleanup_after_query() + { + if (deferred_events) + deferred_events->rewind(); + }; + /* The general cleanup that slave applier may need at the end of session. */ + void cleanup_after_session() + { + if (deferred_events) + delete deferred_events; + }; + /** Helper function to do after statement completion. diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 46c93f7cd20..5f2b5cbf86b 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -226,3 +226,64 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) return error; } + +#ifndef MYSQL_CLIENT +Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL) +{ + my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16); +} + +Deferred_log_events::~Deferred_log_events() +{ + delete_dynamic(&array); +} + +int Deferred_log_events::add(Log_event *ev) +{ + last_added= ev; + insert_dynamic(&array, (uchar*) &ev); + return 0; +} + +bool Deferred_log_events::is_empty() +{ + return array.elements == 0; +} + +bool Deferred_log_events::execute(Relay_log_info *rli) +{ + bool res= false; + + DBUG_ASSERT(rli->deferred_events_collecting); + + rli->deferred_events_collecting= false; + for (uint i= 0; !res && i < array.elements; i++) + { + Log_event *ev= (* (Log_event **) + dynamic_array_ptr(&array, i)); + res= ev->apply_event(rli); + } + rli->deferred_events_collecting= true; + return res; +} + +void Deferred_log_events::rewind() +{ + /* + Reset preceeding Query log event events which execution was + deferred because of slave side filtering. + */ + if (!is_empty()) + { + for (uint i= 0; i < array.elements; i++) + { + Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i); + delete ev; + } + if (array.elements > array.max_element) + freeze_size(&array); + reset_dynamic(&array); + } +} + +#endif diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 4036a41bc60..81a10cca814 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -290,6 +290,24 @@ namespace { }; } + +class Deferred_log_events +{ +private: + DYNAMIC_ARRAY array; + Log_event *last_added; + +public: + Deferred_log_events(Relay_log_info *rli); + ~Deferred_log_events(); + /* queue for exection at Query-log-event time prior the Query */; + int add(Log_event *ev); + bool is_empty(); + bool execute(Relay_log_info *rli); + void rewind(); + bool is_last(Log_event *ev) { return ev == last_added; }; +}; + #endif // NB. number of printed bit values is limited to sizeof(buf) - 1 diff --git a/sql/slave.cc b/sql/slave.cc index be109a385da..0910d196583 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2360,7 +2360,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) used to read info about the relay log's format; it will be deleted when the SQL thread does not need it, i.e. when this thread terminates. */ - if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT) + if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT && + !rli->is_deferred_event(ev)) { DBUG_PRINT("info", ("Deleting the event after it has been executed")); delete ev; @@ -2990,6 +2991,12 @@ pthread_handler_t handle_slave_sql(void *arg) goto err; } thd->init_for_queries(); + thd->rli_slave= rli; + if ((rli->deferred_events_collecting= rpl_filter->is_on())) + { + rli->deferred_events= new Deferred_log_events(rli); + } + thd->temporary_tables = rli->save_temporary_tables; // restore temp tables set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables pthread_mutex_lock(&LOCK_thread_count); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ace78947054..ca24830db63 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -116,6 +116,8 @@ static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, bool send_refresh); static bool has_write_table_with_auto_increment(TABLE_LIST *tables); +static bool +has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables); extern "C" uchar *table_cache_key(const uchar *record, size_t *length, @@ -5471,6 +5473,12 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) *(ptr++)= table->table; } + if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables) + { + if (has_write_table_auto_increment_not_first_in_pk(tables)) + thd->lex->set_stmt_unsafe(); + } + /* We have to emulate LOCK TABLES if we are statement needs prelocking. */ if (thd->lex->requires_prelocking()) { @@ -9065,6 +9073,32 @@ has_write_table_with_auto_increment(TABLE_LIST *tables) return 0; } +/* + Tells if there is a table whose auto_increment column is a part + of a compound primary key while is not the first column in + the table definition. + + @param tables Table list + + @return true if the table exists, fais if does not. +*/ + +static bool +has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables) +{ + for (TABLE_LIST *table= tables; table; table= table->next_global) + { + /* we must do preliminary checks as table->table may be NULL */ + if (!table->placeholder() && + table->table->found_next_number_field && + (table->lock_type >= TL_WRITE_ALLOW_WRITE) + && table->table->s->next_number_keypart != 0) + return 1; + } + + return 0; +} + /* Open and lock system tables for read. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 32e2e90acd7..2f3e8153cbd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -601,7 +601,7 @@ Diagnostics_area::disable_status() THD::THD() :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION, /* statement id */ 0), - Open_tables_state(refresh_version), rli_fake(0), + Open_tables_state(refresh_version), rli_fake(NULL), rli_slave(NULL), lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), sql_log_bin_toplevel(false), @@ -1035,6 +1035,8 @@ THD::~THD() delete rli_fake; rli_fake= NULL; } + if (rli_slave) + rli_slave->cleanup_after_session(); #endif free_root(&main_mem_root, MYF(0)); @@ -1267,6 +1269,10 @@ void THD::cleanup_after_query() /* reset table map for multi-table update */ table_map_for_update= 0; m_binlog_invoker= FALSE; +#ifndef EMBEDDED_LIBRARY + if (rli_slave) + rli_slave->cleanup_after_query(); +#endif } diff --git a/sql/sql_class.h b/sql/sql_class.h index 3c1b2c1330f..31d2c664aae 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1291,6 +1291,8 @@ class THD :public Statement, public: /* Used to execute base64 coded binlog events in MySQL server */ Relay_log_info* rli_fake; + /* Slave applier execution context */ + Relay_log_info* rli_slave; /* Constant for THD::where initialization in the beginning of every query. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 14b778328d2..729a963eef1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2248,6 +2248,11 @@ mysql_execute_command(THD *thd) } DBUG_RETURN(0); } + /* + Execute deferred events first + */ + if (slave_execute_deferred_events(thd)) + DBUG_RETURN(-1); } else { From cdaae1692b1e74c0fdeaaece82e3350a30e3bbd2 Mon Sep 17 00:00:00 2001 From: Nuno Carvalho Date: Fri, 20 Apr 2012 22:25:59 +0100 Subject: [PATCH 12/32] BUG#13979418: SHOW BINLOG EVENTS MAY CRASH THE SERVER The function mysql_show_binlog_events has a local stack variable 'LOG_INFO linfo;', which is assigned to thd->current_linfo, however this variable goes out of scope and is destroyed before clean thd->current_linfo. The problem is solved by moving 'LOG_INFO linfo;' to function scope. --- ...allel_show_binlog_events_purge_logs.result | 13 +++++++ ...arallel_show_binlog_events_purge_logs.test | 35 +++++++++++++++++++ sql/log.h | 5 +++ sql/sql_repl.cc | 5 ++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/rpl/r/rpl_parallel_show_binlog_events_purge_logs.result create mode 100644 mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test diff --git a/mysql-test/suite/rpl/r/rpl_parallel_show_binlog_events_purge_logs.result b/mysql-test/suite/rpl/r/rpl_parallel_show_binlog_events_purge_logs.result new file mode 100644 index 00000000000..b69deb17c4c --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_parallel_show_binlog_events_purge_logs.result @@ -0,0 +1,13 @@ +include/master-slave.inc +[connection master] +[connection slave] +SET DEBUG_SYNC= 'after_show_binlog_events SIGNAL on_show_binlog_events WAIT_FOR end'; +SHOW BINLOG EVENTS; +[connection slave1] +SET DEBUG_SYNC= 'now WAIT_FOR on_show_binlog_events'; +FLUSH LOGS; +SET DEBUG_SYNC= 'now SIGNAL end'; +SET DEBUG_SYNC= 'RESET'; +[connection slave] +SET DEBUG_SYNC= 'RESET'; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test b/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test new file mode 100644 index 00000000000..16d986268c9 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_parallel_show_binlog_events_purge_logs.test @@ -0,0 +1,35 @@ +# BUG#13979418: SHOW BINLOG EVENTS MAY CRASH THE SERVER +# +# The function mysql_show_binlog_events has a local stack variable +# 'LOG_INFO linfo;', which is assigned to thd->current_linfo, however +# this variable goes out of scope and is destroyed before clean +# thd->current_linfo. +# +# This test case runs SHOW BINLOG EVENTS and FLUSH LOGS to make sure +# that with the fix local variable linfo is valid along all +# mysql_show_binlog_events function scope. +# +--source include/have_debug_sync.inc +--source include/master-slave.inc + +--echo [connection slave] +--connection slave +SET DEBUG_SYNC= 'after_show_binlog_events SIGNAL on_show_binlog_events WAIT_FOR end'; +--send SHOW BINLOG EVENTS + +--connection slave1 +--echo [connection slave1] +SET DEBUG_SYNC= 'now WAIT_FOR on_show_binlog_events'; +FLUSH LOGS; +SET DEBUG_SYNC= 'now SIGNAL end'; +SET DEBUG_SYNC= 'RESET'; + +--echo [connection slave] +--connection slave +--disable_result_log +--reap +--enable_result_log +SET DEBUG_SYNC= 'RESET'; + +--connection master +--source include/rpl_end.inc diff --git a/sql/log.h b/sql/log.h index 81342f6e696..9ed5db04e87 100644 --- a/sql/log.h +++ b/sql/log.h @@ -130,6 +130,11 @@ extern TC_LOG_DUMMY tc_log_dummy; class Relay_log_info; +/* + Note that we destroy the lock mutex in the desctructor here. + This means that object instances cannot be destroyed/go out of scope, + until we have reset thd->current_linfo to NULL; + */ typedef struct st_log_info { char log_file_name[FN_REFLEN]; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a2c388ba388..b985805a827 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1454,6 +1454,8 @@ bool mysql_show_binlog_events(THD* thd) IO_CACHE log; File file = -1; int old_max_allowed_packet= thd->variables.max_allowed_packet; + LOG_INFO linfo; + DBUG_ENTER("mysql_show_binlog_events"); Log_event::init_show_field_list(&field_list); @@ -1480,7 +1482,6 @@ bool mysql_show_binlog_events(THD* thd) char search_file_name[FN_REFLEN], *name; const char *log_file_name = lex_mi->log_file_name; pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock(); - LOG_INFO linfo; Log_event* ev; unit->set_limit(thd->lex->current_select); @@ -1572,6 +1573,8 @@ bool mysql_show_binlog_events(THD* thd) pthread_mutex_unlock(log_lock); } + // Check that linfo is still on the function scope. + DEBUG_SYNC(thd, "after_show_binlog_events"); ret= FALSE; From dcb5071b1906d76b4c61d3125ddc7368f3ee8c4f Mon Sep 17 00:00:00 2001 From: Mayank Prasad Date: Sat, 21 Apr 2012 05:23:09 +0530 Subject: [PATCH 13/32] BUG#12427262 : 60961: SHOW TABLES VERY SLOW WHEN NOT IN SYSTEM DISK CACHE Details: - test case bug12427262.test was failing on windows because on windows '/' was not recognized. And this was used in LIKE clause of the query being run in this test case. Fix: - Windows needs '\\\\' for path seperater in mysql. I was not sure how to keep a single query with two different syntax based on platform. So modifying query to make sure it runs correctly on both platform. --- mysql-test/r/bug12427262.result | 19 +++++++++++-------- mysql-test/t/bug12427262.test | 15 +++++++++------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/bug12427262.result b/mysql-test/r/bug12427262.result index f0f7ae46ba2..c541ba0f664 100644 --- a/mysql-test/r/bug12427262.result +++ b/mysql-test/r/bug12427262.result @@ -1,8 +1,8 @@ # # Bug#12427262 : 60961: SHOW TABLES VERY SLOW WHEN NOT IN SYSTEM DISK CACHE. # -create database show_table_db; -use show_table_db; +create database show_table_lw_db; +use show_table_lw_db; create table t1 (c1 int); create table t2 (c1 int); create table t3 (c1 int); @@ -14,9 +14,10 @@ create table t8 (c1 int); create table t9 (c1 int); create table t10 (c1 int); select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_before; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_before; show tables; -Tables_in_show_table_db +Tables_in_show_table_lw_db t1 t10 t2 @@ -28,12 +29,13 @@ t7 t8 t9 select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_after; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_after; select @count_read_after-@count_read_before; @count_read_after-@count_read_before 0.000000000000000000000000000000 show full tables; -Tables_in_show_table_db Table_type +Tables_in_show_table_lw_db Table_type t1 BASE TABLE t10 BASE TABLE t2 BASE TABLE @@ -45,9 +47,10 @@ t7 BASE TABLE t8 BASE TABLE t9 BASE TABLE select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_after; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_after; select @count_read_after-@count_read_before; @count_read_after-@count_read_before 10.000000000000000000000000000000 drop table t1; -drop database show_table_db; +drop database show_table_lw_db; diff --git a/mysql-test/t/bug12427262.test b/mysql-test/t/bug12427262.test index b7193dd1125..aca37a651c4 100644 --- a/mysql-test/t/bug12427262.test +++ b/mysql-test/t/bug12427262.test @@ -6,8 +6,8 @@ --source include/have_perfschema.inc --disable_warnings -create database show_table_db; -use show_table_db; +create database show_table_lw_db; +use show_table_lw_db; create table t1 (c1 int); create table t2 (c1 int); create table t3 (c1 int); @@ -22,14 +22,16 @@ create table t10 (c1 int); # Query PS to know initial read count for frm file. select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_before; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_before; show tables; # Query PS to know read count for frm file after above query. It should # not be changed as FRM file will not be opened for above query. select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_after; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_after; select @count_read_after-@count_read_before; @@ -38,11 +40,12 @@ show full tables; # Query PS to know read count for frm file after above query. COUNT_READ # will be incremented by 1 as FRM file will be opened for above query. select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME -like "%show_table_db/%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' into @count_read_after; +like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM' +into @count_read_after; select @count_read_after-@count_read_before; --disable_warnings drop table t1; -drop database show_table_db; +drop database show_table_lw_db; --enable_warnings From 6d74c922af3d37debfe3a42803d5c86b56dd936e Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Sat, 21 Apr 2012 14:19:06 +0300 Subject: [PATCH 14/32] merge bug11754117-45670 fixes from 5.1: fixing result files. --- .../suite/rpl/r/rpl_auto_increment_bug45679.result | 9 +++++++-- .../suite/rpl/r/rpl_filter_tables_not_exist.result | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result index 75f4e661dc1..198ecfb6724 100644 --- a/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result +++ b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result @@ -9,10 +9,10 @@ set @@binlog_format=statement; *** autoincrement field is not the first in PK warning must be there: *** insert into tm set b=null, a=1; Warnings: -Note 1592 Statement may not be safe to log in statement format. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe. show warnings; Level Code Message -Note 1592 Statement may not be safe to log in statement format. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe. *** no warning when autoincrement is the first in PK insert into ti set b=null, a=1; show warnings; @@ -26,9 +26,14 @@ end// select multi_part_pk_with_autoinc (3); multi_part_pk_with_autoinc (3) 3 +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe. *** autoincrement field is not the first in PK warning must be there: *** show warnings; Level Code Message +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe. set @@binlog_format=mixed; insert into tm set b=null, a=2; drop table tm, ti; diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result index f0dc97b71f2..025ef690ed7 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result +++ b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result @@ -126,7 +126,7 @@ SET @c=2; SET @@rand_seed1=10000000, @@rand_seed2=1000000; INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); Warnings: -Note 1592 Statement may not be safe to log in statement format. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. SELECT b into @b FROM test.t5; UPDATE test.t1 SET a=2; SELECT a AS 'ONE' into @a FROM test.t_slave; From da7436a2a88a94440b746ad6600450569a50923b Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Sat, 21 Apr 2012 15:06:06 +0300 Subject: [PATCH 15/32] merge bug11754117-45670 fixes from 5.1: fixing comments in sql_lex.h. --- sql/sql_lex.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 992ed551564..111a22c7ff9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1330,7 +1330,8 @@ public: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS, /** - INSERT into auto-inc field which is not the first field in the table. + INSERT into auto-inc field which is not the first part of composed + primary key. */ BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST, From bd0c38064faf52e65ee8d2044f15b6393b44522d Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Mon, 23 Apr 2012 11:51:19 +0300 Subject: [PATCH 16/32] BUG#11754117 rpl_auto_increment_bug45679.test is refined due to not fixed in 5.1 Bug11749859-39934. --- mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result | 2 +- mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result index 75f4e661dc1..e2b3206eb02 100644 --- a/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result +++ b/mysql-test/suite/rpl/r/rpl_auto_increment_bug45679.result @@ -26,7 +26,7 @@ end// select multi_part_pk_with_autoinc (3); multi_part_pk_with_autoinc (3) 3 -*** autoincrement field is not the first in PK warning must be there: *** +*** No warnings in 5.1 because of Bug11749859-39934 *** show warnings; Level Code Message set @@binlog_format=mixed; diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test index 6996e1c73c7..0df086ddbfa 100644 --- a/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_bug45679.test @@ -35,7 +35,7 @@ end// delimiter ;// select multi_part_pk_with_autoinc (3); ---echo *** autoincrement field is not the first in PK warning must be there: *** +--echo *** No warnings in 5.1 because of Bug11749859-39934 *** show warnings; set @@binlog_format=mixed; From 2415d955c8fff4a2001f4d1774a75f156b787e7c Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Mon, 23 Apr 2012 06:39:16 -0400 Subject: [PATCH 17/32] Bug#12677594 - 61575: INNODB: WARNING: IO_SETUP() FAILED WITH EAGAIN. rb://1033 approved by: Marko Makela Check return value from os_aio_init() and refuse to start if it fails. --- storage/innobase/srv/srv0start.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index 343e41fe376..86669a50895 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -1364,10 +1364,18 @@ innobase_start_or_create_for_mysql(void) } # endif /* __WIN__ */ - os_aio_init(io_limit, - srv_n_read_io_threads, - srv_n_write_io_threads, - SRV_MAX_N_PENDING_SYNC_IOS); + if (!os_aio_init(io_limit, + srv_n_read_io_threads, + srv_n_write_io_threads, + SRV_MAX_N_PENDING_SYNC_IOS)) { + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Fatal error: cannot initialize AIO" + " sub-system\n"); + + return(DB_ERROR); + } fil_init(srv_file_per_table ? 50000 : 5000, srv_max_n_open_files); From 678f221cb9ac3ba18b70568077d8979adb1ac44c Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Mon, 23 Apr 2012 12:52:14 +0200 Subject: [PATCH 18/32] Allow Windows absolute paths in N:\ formatfor the --vardir option --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 43734d04286..927a2ebfa91 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1442,7 +1442,7 @@ sub command_line_setup { # We make the path absolute, as the server will do a chdir() before usage unless ( $opt_vardir =~ m,^/, or - (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:/,i) ) + (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:[/\\],i) ) { # Make absolute path, relative test dir $opt_vardir= "$glob_mysql_test_dir/$opt_vardir"; From e881e03e01e1c27fa4d7715aec750d34af56aadd Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 23 Apr 2012 16:26:22 +0300 Subject: [PATCH 19/32] Bug #59148 - made tests experimental Fixed a cmake 2.8.8 compilation problem. --- configure.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.cmake b/configure.cmake index c3cc787ebc8..b8fa70db203 100644 --- a/configure.cmake +++ b/configure.cmake @@ -149,7 +149,9 @@ IF(UNIX) SET(CMAKE_REQUIRED_LIBRARIES ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT}) - LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES) + IF(NOT ${CMAKE_REQUIRED_LIBRARIES} MATCHES '') + LIST(REMOVE_DUPLICATES ${CMAKE_REQUIRED_LIBRARIES}) + ENDIF() LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT}) OPTION(WITH_LIBWRAP "Compile with tcp wrappers support" OFF) From b872ce0312022b5ac86a368305c34ce9fda7d720 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 23 Apr 2012 17:18:55 +0300 Subject: [PATCH 20/32] Fixed a cmake compile problem because of the 2.8.8 fix. --- configure.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.cmake b/configure.cmake index b8fa70db203..5b1afd66439 100644 --- a/configure.cmake +++ b/configure.cmake @@ -149,8 +149,9 @@ IF(UNIX) SET(CMAKE_REQUIRED_LIBRARIES ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT}) - IF(NOT ${CMAKE_REQUIRED_LIBRARIES} MATCHES '') - LIST(REMOVE_DUPLICATES ${CMAKE_REQUIRED_LIBRARIES}) + LIST(LENGTH CMAKE_REQUIRED_LIBRARIES required_libs_length) + IF(${required_libs_length} GREATER 0) + LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES) ENDIF() LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT}) From 08ead005b11a2806e45f395dd4b36ecd0f471b7c Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Mon, 23 Apr 2012 22:15:29 -0400 Subject: [PATCH 21/32] Bug#13990648: 65061: LRU FLUSH RATE CALCULATION IS BASED ON INVALID VALUES rb://1043 approved by: Sunny Bains Two internal counters were incremented twice for a single operations. The counters are: srv_buf_pool_flushed buf_lru_flush_page_count --- storage/innobase/buf/buf0flu.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c index 6e8e8fdda5a..7cd09d6675e 100644 --- a/storage/innobase/buf/buf0flu.c +++ b/storage/innobase/buf/buf0flu.c @@ -1750,8 +1750,6 @@ buf_flush_batch( } #endif /* UNIV_DEBUG */ - srv_buf_pool_flushed += count; - return(count); } @@ -1778,13 +1776,6 @@ buf_flush_common( #endif /* UNIV_DEBUG */ srv_buf_pool_flushed += page_count; - - if (flush_type == BUF_FLUSH_LRU) { - /* We keep track of all flushes happening as part of LRU - flush. When estimating the desired rate at which flush_list - should be flushed we factor in this value. */ - buf_lru_flush_page_count += page_count; - } } /******************************************************************//** From 3f98e95354b6d1c55a824bb1b314e3bb8c465ef0 Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Thu, 26 Apr 2012 19:34:03 +0530 Subject: [PATCH 22/32] BUG#13812374 - RPL.RPL_REPORT_PORT FAILS OCCASIONALLY ON PB2 Problem - The failure on PB2 is possbily due to the port number being still in use even after the server restarts which is not reflected in the server restart. Fix - The problem is fixed by starting the servers forcefully using the option file and also the parameters for the server restart is passed correctly. mysql-test/suite/rpl/t/rpl_report_port-master.opt: Option file for the master. --- mysql-test/suite/rpl/r/rpl_report_port.result | 4 ++-- mysql-test/suite/rpl/t/rpl_report_port-master.opt | 1 + mysql-test/suite/rpl/t/rpl_report_port.test | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/rpl/t/rpl_report_port-master.opt diff --git a/mysql-test/suite/rpl/r/rpl_report_port.result b/mysql-test/suite/rpl/r/rpl_report_port.result index d9887f41ff9..6a9ac341780 100644 --- a/mysql-test/suite/rpl/r/rpl_report_port.result +++ b/mysql-test/suite/rpl/r/rpl_report_port.result @@ -3,8 +3,8 @@ include/master-slave.inc include/rpl_restart_server.inc [server_number=2 parameters: --report-port=9000] include/start_slave.inc [Slave restarted with the report-port set to some value] -include/assert.inc [The value shown for the slave's port number is 9000 which is the value set for report-port.] -include/rpl_restart_server.inc [server_number=2 parameters: --report-port=] +include/assert.inc [The value shown for the slave's port number is user specified port number which is the value set for report-port.] +include/rpl_restart_server.inc [server_number=2] include/start_slave.inc [Slave restarted with the report-port set to the value of slave's port number] include/assert.inc [The default value shown for the slave's port number is the actual port number of the slave.] diff --git a/mysql-test/suite/rpl/t/rpl_report_port-master.opt b/mysql-test/suite/rpl/t/rpl_report_port-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_report_port-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/suite/rpl/t/rpl_report_port.test b/mysql-test/suite/rpl/t/rpl_report_port.test index 379f9aed946..12c34ce01b1 100644 --- a/mysql-test/suite/rpl/t/rpl_report_port.test +++ b/mysql-test/suite/rpl/t/rpl_report_port.test @@ -38,21 +38,23 @@ connection master; # 9000 is the value of the port we should get. --let $report_port= query_get_value(SHOW SLAVE HOSTS, Port, 1) ---let assert_text= The value shown for the slave's port number is 9000 which is the value set for report-port. +--let assert_text= The value shown for the slave's port number is user specified port number which is the value set for report-port. --let assert_cond= $report_port = "9000" --source include/assert.inc - # Start the server with the report-port being passed with no value. So on SHOW SLAVE HOSTS # on the master the value of slave's port should be the actual value of the slave port. +connection master; --let $rpl_server_number= 2 ---let $rpl_server_parameters= --report-port= +--let $rpl_server_parameters= --source include/rpl_restart_server.inc connection slave; --source include/start_slave.inc +connection master; +sync_slave_with_master; --echo [Slave restarted with the report-port set to the value of slave's port number] connection master; From 1a2cf649dc411b47122419cb9e8c8ef1a26ae91a Mon Sep 17 00:00:00 2001 From: irana Date: Thu, 26 Apr 2012 08:17:14 -0700 Subject: [PATCH 23/32] InnoDB: Adjust error message when a dropped tablespace is accessed. --- storage/innodb_plugin/fil/fil0fil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index eebfbd9ccad..6f2ab938042 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -1853,7 +1853,7 @@ fil_inc_pending_ops( if (space == NULL) { fprintf(stderr, - "InnoDB: Error: trying to do ibuf merge to a" + "InnoDB: Error: trying to do an operation on a" " dropped tablespace %lu\n", (ulong) id); } From 08e7444e549722f61dd90fdf23ce05632c72044e Mon Sep 17 00:00:00 2001 From: Yasufumi Kinoshita Date: Fri, 27 Apr 2012 19:38:13 +0900 Subject: [PATCH 24/32] Bug#11758510 (#50723): INNODB CHECK TABLE FATAL SEMAPHORE WAIT TIMEOUT POSSIBLY TOO SHORT FOR BI Fixed not to check timeout during the check table. --- storage/innobase/dict/dict0load.c | 4 ++-- storage/innobase/include/srv0srv.h | 1 + storage/innobase/row/row0mysql.c | 4 ++-- storage/innobase/sync/sync0arr.c | 5 +++++ storage/innodb_plugin/dict/dict0load.c | 4 ++-- storage/innodb_plugin/handler/ha_innodb.cc | 4 ++-- storage/innodb_plugin/include/srv0srv.h | 1 + storage/innodb_plugin/sync/sync0arr.c | 5 +++++ 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 7e820cfb08d..3c3c0d10c7c 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -150,7 +150,7 @@ dict_print(void) monitor printout */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); mutex_enter(&(dict_sys->mutex)); @@ -178,7 +178,7 @@ loop: /* Restore the fatal semaphore wait timeout */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); return; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 811074b2be8..aa6c88e0538 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -173,6 +173,7 @@ extern ibool srv_print_latch_waits; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; +#define SRV_SEMAPHORE_WAIT_EXTENSION 7200 extern ulint srv_dml_needed_delay; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 6148b01af9d..16fd2b3b482 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -4165,7 +4165,7 @@ row_check_table_for_mysql( /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); index = dict_table_get_first_index(table); @@ -4223,7 +4223,7 @@ row_check_table_for_mysql( /* Restore the fatal lock wait timeout after CHECK TABLE. */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); prebuilt->trx->op_info = ""; diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 93a7398f252..60a96fe4388 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -931,6 +931,11 @@ sync_array_print_long_waits( ibool fatal = FALSE; double longest_diff = 0; + /* For huge tables, skip the check during CHECK TABLE etc... */ + if (fatal_timeout > SRV_SEMAPHORE_WAIT_EXTENSION) { + return(FALSE); + } + for (i = 0; i < sync_primary_wait_array->n_cells; i++) { double diff; diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c index 7a0b6edcb08..7231fadabe1 100644 --- a/storage/innodb_plugin/dict/dict0load.c +++ b/storage/innodb_plugin/dict/dict0load.c @@ -164,7 +164,7 @@ dict_print(void) monitor printout */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); mutex_enter(&(dict_sys->mutex)); @@ -192,7 +192,7 @@ loop: /* Restore the fatal semaphore wait timeout */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); return; diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index f16b9fabd20..30448bccf7b 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -8148,7 +8148,7 @@ ha_innobase::check( /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); for (index = dict_table_get_first_index(prebuilt->table); @@ -8244,7 +8244,7 @@ ha_innobase::check( /* Restore the fatal lock wait timeout after CHECK TABLE. */ mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION; mutex_exit(&kernel_mutex); prebuilt->trx->op_info = ""; diff --git a/storage/innodb_plugin/include/srv0srv.h b/storage/innodb_plugin/include/srv0srv.h index 7c63a5f0d45..1a9f54882c5 100644 --- a/storage/innodb_plugin/include/srv0srv.h +++ b/storage/innodb_plugin/include/srv0srv.h @@ -244,6 +244,7 @@ extern ibool srv_print_latch_waits; extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; +#define SRV_SEMAPHORE_WAIT_EXTENSION 7200 extern ulint srv_dml_needed_delay; extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, diff --git a/storage/innodb_plugin/sync/sync0arr.c b/storage/innodb_plugin/sync/sync0arr.c index 13970023573..90ea50b641b 100644 --- a/storage/innodb_plugin/sync/sync0arr.c +++ b/storage/innodb_plugin/sync/sync0arr.c @@ -927,6 +927,11 @@ sync_array_print_long_waits( ibool fatal = FALSE; double longest_diff = 0; + /* For huge tables, skip the check during CHECK TABLE etc... */ + if (fatal_timeout > SRV_SEMAPHORE_WAIT_EXTENSION) { + return(FALSE); + } + for (i = 0; i < sync_primary_wait_array->n_cells; i++) { double diff; From 6fa011056abf534bf3d544cdef14f3a539777b6d Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 27 Apr 2012 18:42:27 +0400 Subject: [PATCH 25/32] Follow-up for Bug#12762885 - 61713: MYSQL WILL NOT BIND TO "LOCALHOST" IF LOCALHOST IS BOTH IPV4/IPV6 ENABLED. The original patch removed default value of the bind-address option. So, the default value became NULL. By coincedence NULL resolves to 0.0.0.0 and ::, and since the server chooses first IPv4-address, 0.0.0.0 is choosen. So, there was no change in the behaviour. This patch restores default value of the bind-address option to "0.0.0.0". --- sql/mysqld.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 547378d4661..e90bd8dad33 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1841,6 +1841,9 @@ static void network_init(void) struct addrinfo *ai, *a; struct addrinfo hints; + if (!my_bind_addr_str) + my_bind_addr_str= (char *) "0.0.0.0"; + sql_print_information("Server hostname (bind-address): '%s'; port: %d", my_bind_addr_str, mysqld_port); From 25cdec81e082049a668552f631fa32a838d915e3 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 27 Apr 2012 19:14:28 +0400 Subject: [PATCH 26/32] Proper follow-up for Bug#12762885 - 61713: MYSQL WILL NOT BIND TO "LOCALHOST" IF LOCALHOST IS BOTH IPV4/IPV6 ENABLED. The original patch removed default value of the bind-address option. So, the default value became NULL. By coincedence NULL resolves to 0.0.0.0 and ::, and since the server chooses first IPv4-address, 0.0.0.0 is choosen. So, there was no change in the behaviour. This patch restores default value of the bind-address option to "0.0.0.0". --- mysql-test/r/mysqld--help-notwin.result | 2 +- mysql-test/r/mysqld--help-win.result | 2 +- sql/mysqld.cc | 8 +------- sql/mysqld.h | 1 + sql/sys_vars.cc | 5 +++++ 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 36649cf761d..ac8edfc5083 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -747,7 +747,7 @@ autocommit TRUE automatic-sp-privileges TRUE back-log 50 big-tables FALSE -bind-address (No default value) +bind-address 0.0.0.0 binlog-cache-size 32768 binlog-direct-non-transactional-updates FALSE binlog-format STATEMENT diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index db7dd264b76..d47b6f0c1a5 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -755,7 +755,7 @@ autocommit TRUE automatic-sp-privileges TRUE back-log 50 big-tables FALSE -bind-address (No default value) +bind-address 0.0.0.0 binlog-cache-size 32768 binlog-direct-non-transactional-updates FALSE binlog-format STATEMENT diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e90bd8dad33..936167280e0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -341,7 +341,7 @@ static char *default_character_set_name; static char *character_set_filesystem_name; static char *lc_messages; static char *lc_time_names_name; -static char *my_bind_addr_str; +char *my_bind_addr_str; static char *default_collation_name; char *default_storage_engine; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; @@ -1841,9 +1841,6 @@ static void network_init(void) struct addrinfo *ai, *a; struct addrinfo hints; - if (!my_bind_addr_str) - my_bind_addr_str= (char *) "0.0.0.0"; - sql_print_information("Server hostname (bind-address): '%s'; port: %d", my_bind_addr_str, mysqld_port); @@ -5713,9 +5710,6 @@ struct my_option my_long_options[]= {"autocommit", 0, "Set default value for autocommit (0 or 1)", &opt_autocommit, &opt_autocommit, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, NULL}, - {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", - &my_bind_addr_str, &my_bind_addr_str, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, " "and exclude all others not explicitly mentioned.", diff --git a/sql/mysqld.h b/sql/mysqld.h index 2604e889ebd..7fef4c6af82 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -146,6 +146,7 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, extern const char *log_output_str; extern const char *log_backup_output_str; extern char *mysql_home_ptr, *pidfile_name_ptr; +extern char *my_bind_addr_str; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; extern char default_logfile_name[FN_REFLEN]; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f15664bca10..9c7421c46f2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -308,6 +308,11 @@ static Sys_var_charptr Sys_basedir( READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT(0)); +static Sys_var_charptr Sys_my_bind_addr( + "bind_address", "IP address to bind to.", + READ_ONLY GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG), + IN_FS_CHARSET, DEFAULT("0.0.0.0")); + static Sys_var_ulong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " From 476762bd7b3bbe6c1f89858174c0dde5e44b361b Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 27 Apr 2012 21:07:53 +0400 Subject: [PATCH 27/32] Revert two follow-ups for Bug#12762885: - alexander.nozdrin@oracle.com-20120427151428-7llk1mlwx8xmbx0t - alexander.nozdrin@oracle.com-20120427144227-kltwiuu8snds4j3l. --- mysql-test/r/mysqld--help-notwin.result | 2 +- mysql-test/r/mysqld--help-win.result | 2 +- sql/mysqld.cc | 5 ++++- sql/mysqld.h | 1 - sql/sys_vars.cc | 5 ----- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index ac8edfc5083..36649cf761d 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -747,7 +747,7 @@ autocommit TRUE automatic-sp-privileges TRUE back-log 50 big-tables FALSE -bind-address 0.0.0.0 +bind-address (No default value) binlog-cache-size 32768 binlog-direct-non-transactional-updates FALSE binlog-format STATEMENT diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index d47b6f0c1a5..db7dd264b76 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -755,7 +755,7 @@ autocommit TRUE automatic-sp-privileges TRUE back-log 50 big-tables FALSE -bind-address 0.0.0.0 +bind-address (No default value) binlog-cache-size 32768 binlog-direct-non-transactional-updates FALSE binlog-format STATEMENT diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 936167280e0..547378d4661 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -341,7 +341,7 @@ static char *default_character_set_name; static char *character_set_filesystem_name; static char *lc_messages; static char *lc_time_names_name; -char *my_bind_addr_str; +static char *my_bind_addr_str; static char *default_collation_name; char *default_storage_engine; static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; @@ -5710,6 +5710,9 @@ struct my_option my_long_options[]= {"autocommit", 0, "Set default value for autocommit (0 or 1)", &opt_autocommit, &opt_autocommit, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, NULL}, + {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", + &my_bind_addr_str, &my_bind_addr_str, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, " "and exclude all others not explicitly mentioned.", diff --git a/sql/mysqld.h b/sql/mysqld.h index 7fef4c6af82..2604e889ebd 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -146,7 +146,6 @@ extern char *opt_backup_history_logname, *opt_backup_progress_logname, extern const char *log_output_str; extern const char *log_backup_output_str; extern char *mysql_home_ptr, *pidfile_name_ptr; -extern char *my_bind_addr_str; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; extern char default_logfile_name[FN_REFLEN]; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9c7421c46f2..f15664bca10 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -308,11 +308,6 @@ static Sys_var_charptr Sys_basedir( READ_ONLY GLOBAL_VAR(mysql_home_ptr), CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT(0)); -static Sys_var_charptr Sys_my_bind_addr( - "bind_address", "IP address to bind to.", - READ_ONLY GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG), - IN_FS_CHARSET, DEFAULT("0.0.0.0")); - static Sys_var_ulong Sys_binlog_cache_size( "binlog_cache_size", "The size of the transactional cache for " "updates to transactional engines for the binary log. " From 95205bbaffed8adb80185af5fa24aef697b6c9d4 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Fri, 27 Apr 2012 21:14:35 +0400 Subject: [PATCH 28/32] Third attempt to do a follow-up for Bug#12762885 - 61713: MYSQL WILL NOT BIND TO "LOCALHOST" IF LOCALHOST IS BOTH IPV4/IPV6 ENABLED. Previous commit comments were wrong. The default value has always been NULL. The original patch for Bug#12762885 just makes it visible in the logs. This patch uses "0.0.0.0" string if bind-address is not set. --- sql/mysqld.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 547378d4661..63656460f42 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1840,9 +1840,13 @@ static void network_init(void) { struct addrinfo *ai, *a; struct addrinfo hints; + const char *bind_address= my_bind_addr_str; + + if (!bind_address) + bind_address= "0.0.0.0"; sql_print_information("Server hostname (bind-address): '%s'; port: %d", - my_bind_addr_str, mysqld_port); + bind_address, mysqld_port); // Get list of IP-addresses associated with the server hostname. bzero(&hints, sizeof (hints)); @@ -1851,7 +1855,7 @@ static void network_init(void) hints.ai_family= AF_UNSPEC; my_snprintf(port_buf, NI_MAXSERV, "%d", mysqld_port); - if (getaddrinfo(my_bind_addr_str, port_buf, &hints, &ai)) + if (getaddrinfo(bind_address, port_buf, &hints, &ai)) { sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */ sql_print_error("Can't start server: cannot resolve hostname!"); @@ -1871,7 +1875,7 @@ static void network_init(void) } sql_print_information(" - '%s' resolves to '%s';", - my_bind_addr_str, ip_addr); + bind_address, ip_addr); } /* From b757c13078ec88bb734c8697a9e3ecd870934f8a Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Fri, 4 May 2012 12:29:49 +0530 Subject: [PATCH 29/32] In perl, to break out of a foreach loop we need to use the keyword "last" and not "break". Fixing the failing test case. --- mysql-test/suite/innodb/t/innodb_bug12902967.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb/t/innodb_bug12902967.test b/mysql-test/suite/innodb/t/innodb_bug12902967.test index 7bc5727a7a6..e9d832f3c19 100644 --- a/mysql-test/suite/innodb/t/innodb_bug12902967.test +++ b/mysql-test/suite/innodb/t/innodb_bug12902967.test @@ -33,7 +33,7 @@ foreach $line (reverse @lines) { ++$count; print "$line"; if ($count == 2) { - break; + last; } } } From daafaa0f86208fb5ddb13468e79772abef46cbd1 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Fri, 4 May 2012 18:33:34 +0530 Subject: [PATCH 30/32] Bug #11754178 45740: MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM Problem Statement: ------------------ mysqldump is not having the dump stmts for general_log and slow_log tables. That is because of the fix for Bug#26121. Hence, after dropping the mysql database, and applying the dump by enabling the logging, "'general_log' table not found" errors are logged into the server log file. Analysis: --------- As part of the fix for Bug#26121, we skipped the dumping of tables for general_log and slow_log, because the data dump of those tables are taking LOCKS, which is not allowed for log tables. Fix: ---- We came up with an approach that instead of taking both meta data and data dump information for those tables, take only the meta data dump which doesn't need LOCKS. As part of fixing the issue we came up with below algorithm. Design before fix: 1) mysql database is having tables like db, event,... general_log, ... slow_log... 2) Skip general_log and slow_log while preparing the tables list 3) Take the TL_READ lock on tables which are present in the table list and do 'show create table'. 4) Release the lock. Design with the fix: 1) mysql database is having tables like db, event,... general_log, ... slow_log... 2) Skip general_log and slow_log while preparing the tables list 3) Explicitly call the 'show create table' for general_log and slow_log 3) Take the TL_READ lock on tables which are present in the table list and do 'show create table'. 4) Release the lock. While taking the meta data dump for general_log and slow_log the "CREATE TABLE" is replaced with "CREATE TABLE IF NOT EXISTS". This is because we skipped "DROP TABLE" for those tables, "DROP TABLE" fails for these tables if logging is enabled. Customer is applying the dump by enabling logging so, if the dump has "DROP TABLE" it will fail. Hence, removed the "DROP TABLE" stmts for those tables. After the fix we could observe "Table 'mysql.general_log' doesn't exist" errors initially that is because in the customer scenario they are dropping the mysql database by enabling the logging, Hence, those errors are expected. Once we apply the dump which is taken before the "drop database mysql", the errors will not be there. client/mysqldump.c: In get_table_structure() added code to skip the DROP TABLE stmts for general_log and slow_log tables, because when logging is enabled those stmts will fail. And replaced CREATE TABLE with CREATE IF NOT EXISTS for those tables, just to make sure CREATE stmt for those tables doesn't fail since we removed DROP stmts for those tables. In dump_all_tables_in_db() added code to call get_table_structure() for general_log and slow_log tables. mysql-test/r/mysqldump.result: Added a test as part of fix for Bug #11754178 mysql-test/t/mysqldump.test: Added a test as part of fix for Bug #11754178 --- client/mysqldump.c | 58 ++++++++++++++++++++++++++++++----- mysql-test/r/mysqldump.result | 42 +++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 29 ++++++++++++++++-- 3 files changed, 118 insertions(+), 11 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 8601b533849..dc124f1b335 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -84,6 +84,15 @@ #define IGNORE_DATA 0x01 /* don't dump data for this table */ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ +/* general_log or slow_log tables under mysql database */ +static inline my_bool general_log_or_slow_log_tables(const char *db, + const char *table) +{ + return (strcmp(db, "mysql") == 0) && + ((strcmp(table, "general_log") == 0) || + (strcmp(table, "slow_log") == 0)); +} + static void add_load_option(DYNAMIC_STRING *str, const char *option, const char *option_value); static ulong find_set(TYPELIB *lib, const char *x, uint length, @@ -2458,6 +2467,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, "TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'"; FILE *sql_file= md_result_file; int len; + my_bool is_log_table; MYSQL_RES *result; MYSQL_ROW row; DBUG_ENTER("get_table_structure"); @@ -2542,9 +2552,12 @@ static uint get_table_structure(char *table, char *db, char *table_type, /* Even if the "table" is a view, we do a DROP TABLE here. The view-specific code below fills in the DROP VIEW. + We will skip the DROP TABLE for general_log and slow_log, since + those stmts will fail, in case we apply dump by enabling logging. */ - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", - opt_quoted_table); + if (!general_log_or_slow_log_tables(db, table)) + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", + opt_quoted_table); check_io(sql_file); } @@ -2656,12 +2669,25 @@ static uint get_table_structure(char *table, char *db, char *table_type, row= mysql_fetch_row(result); - fprintf(sql_file, (opt_compatible_mode & 3) ? "%s;\n" : - "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" - "/*!40101 SET character_set_client = utf8 */;\n" - "%s;\n" - "/*!40101 SET character_set_client = @saved_cs_client */;\n", - row[1]); + is_log_table= general_log_or_slow_log_tables(db, table); + if (is_log_table) + row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */ + if (opt_compatible_mode & 3) + { + fprintf(sql_file, + is_log_table ? "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n", + row[1]); + } + else + { + fprintf(sql_file, + "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" + "/*!40101 SET character_set_client = utf8 */;\n" + "%s%s;\n" + "/*!40101 SET character_set_client = @saved_cs_client */;\n", + is_log_table ? "CREATE TABLE IF NOT EXISTS " : "", + row[1]); + } check_io(sql_file); mysql_free_result(result); @@ -4261,6 +4287,22 @@ static int dump_all_tables_in_db(char *database) if (opt_xml) print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS); + if (strcmp(database, "mysql") == 0) + { + char table_type[NAME_LEN]; + char ignore_flag; + uint num_fields; + num_fields= get_table_structure((char *) "general_log", + database, table_type, &ignore_flag); + if (num_fields == 0) + verbose_msg("-- Warning: get_table_structure() failed with some internal " + "error for 'general_log' table\n"); + num_fields= get_table_structure((char *) "slow_log", + database, table_type, &ignore_flag); + if (num_fields == 0) + verbose_msg("-- Warning: get_table_structure() failed with some internal " + "error for 'slow_log' table\n"); + } if (lock_tables) { DYNAMIC_STRING query; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 1d4a5783c3f..fac94e855a4 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -5067,5 +5067,47 @@ RETURN CONCAT(']]]]>, ', s, '!') DROP DATABASE BUG52792; USE test; # +# Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM +# +SET @old_log_output_state= @@global.log_output; +SET @old_general_log_state= @@global.general_log; +SET @old_slow_query_log_state= @@global.slow_query_log; +call mtr.add_suppression("Failed to write to mysql.general_log"); +SET @@global.log_output="TABLE"; +SET @@global.general_log='ON'; +SET @@global.slow_query_log='ON'; +DROP DATABASE mysql; +Warnings: +Error 1146 Table 'mysql.proc' doesn't exist +Error 1146 Table 'mysql.event' doesn't exist +SHOW CREATE TABLE mysql.general_log; +Table Create Table +general_log CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `thread_id` int(11) NOT NULL, + `server_id` int(10) unsigned NOT NULL, + `command_type` varchar(64) NOT NULL, + `argument` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log' +SHOW CREATE TABLE mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) NOT NULL, + `last_insert_id` int(11) NOT NULL, + `insert_id` int(11) NOT NULL, + `server_id` int(10) unsigned NOT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +SET @@global.log_output= @old_log_output_state; +SET @@global.slow_query_log= @old_slow_query_log_state; +SET @@global.general_log= @old_general_log_state; +# # End of 5.1 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 20c788e3b9a..7393ca88f0a 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2308,9 +2308,32 @@ DROP DATABASE BUG52792; USE test; +# Wait till we reached the initial number of concurrent sessions +--source include/wait_until_count_sessions.inc + +--echo # +--echo # Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM +--echo # +SET @old_log_output_state= @@global.log_output; +SET @old_general_log_state= @@global.general_log; +SET @old_slow_query_log_state= @@global.slow_query_log; + +call mtr.add_suppression("Failed to write to mysql.general_log"); +--exec $MYSQL_DUMP -uroot --all-databases > $MYSQLTEST_VARDIR/tmp/bug45740.sql +# Make log_output as table and enable general_log and slow_log +SET @@global.log_output="TABLE"; +SET @@global.general_log='ON'; +SET @@global.slow_query_log='ON'; +DROP DATABASE mysql; +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug45740.sql +SHOW CREATE TABLE mysql.general_log; +SHOW CREATE TABLE mysql.slow_log; +--remove_file $MYSQLTEST_VARDIR/tmp/bug45740.sql + +SET @@global.log_output= @old_log_output_state; +SET @@global.slow_query_log= @old_slow_query_log_state; +SET @@global.general_log= @old_general_log_state; + --echo # --echo # End of 5.1 tests --echo # - -# Wait till we reached the initial number of concurrent sessions ---source include/wait_until_count_sessions.inc From e7364ec29c522b5d98951b851ca3cc62a9f46d59 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Mon, 7 May 2012 16:46:44 +0530 Subject: [PATCH 31/32] Bug #11754178 45740: MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM Problem Statement: ------------------ mysqldump is not having the dump stmts for general_log and slow_log tables. That is because of the fix for Bug#26121. Hence, after dropping the mysql database, and applying the dump by enabling the logging, "'general_log' table not found" errors are logged into the server log file. Analysis: --------- As part of the fix for Bug#26121, we skipped the dumping of tables for general_log and slow_log, because the data dump of those tables are taking LOCKS, which is not allowed for log tables. Fix: ---- We came up with an approach that instead of taking both meta data and data dump information for those tables, take only the meta data dump which doesn't need LOCKS. As part of fixing the issue we came up with below algorithm. Design before fix: 1) mysql database is having tables like db, event,... general_log, ... slow_log... 2) Skip general_log and slow_log while preparing the tables list 3) Take the TL_READ lock on tables which are present in the table list and do 'show create table'. 4) Release the lock. Design with the fix: 1) mysql database is having tables like db, event,... general_log, ... slow_log... 2) Skip general_log and slow_log while preparing the tables list 3) Explicitly call the 'show create table' for general_log and slow_log 3) Take the TL_READ lock on tables which are present in the table list and do 'show create table'. 4) Release the lock. While taking the meta data dump for general_log and slow_log the "CREATE TABLE" is replaced with "CREATE TABLE IF NOT EXISTS". This is because we skipped "DROP TABLE" for those tables, "DROP TABLE" fails for these tables if logging is enabled. Customer is applying the dump by enabling logging so, if the dump has "DROP TABLE" it will fail. Hence, removed the "DROP TABLE" stmts for those tables. After the fix we could observe "Table 'mysql.general_log' doesn't exist" errors initially that is because in the customer scenario they are dropping the mysql database by enabling the logging, Hence, those errors are expected. Once we apply the dump which is taken before the "drop database mysql", the errors will not be there. client/mysqldump.c: In get_table_structure() added code to skip the DROP TABLE stmts for general_log and slow_log tables, because when logging is enabled those stmts will fail. And replaced CREATE TABLE with CREATE IF NOT EXISTS for those tables, just to make sure CREATE stmt for those tables doesn't fail since we removed DROP stmts for those tables. In dump_all_tables_in_db() added code to call get_table_structure() for general_log and slow_log tables. mysql-test/r/mysqldump.result: Added a test as part of fix for Bug #11754178 mysql-test/t/mysqldump.test: Added a test as part of fix for Bug #11754178 --- client/mysqldump.c | 58 ++++++++++++++++++++++++++++++----- mysql-test/r/mysqldump.result | 42 +++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 29 ++++++++++++++++-- 3 files changed, 118 insertions(+), 11 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 8601b533849..dc124f1b335 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -84,6 +84,15 @@ #define IGNORE_DATA 0x01 /* don't dump data for this table */ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ +/* general_log or slow_log tables under mysql database */ +static inline my_bool general_log_or_slow_log_tables(const char *db, + const char *table) +{ + return (strcmp(db, "mysql") == 0) && + ((strcmp(table, "general_log") == 0) || + (strcmp(table, "slow_log") == 0)); +} + static void add_load_option(DYNAMIC_STRING *str, const char *option, const char *option_value); static ulong find_set(TYPELIB *lib, const char *x, uint length, @@ -2458,6 +2467,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, "TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'"; FILE *sql_file= md_result_file; int len; + my_bool is_log_table; MYSQL_RES *result; MYSQL_ROW row; DBUG_ENTER("get_table_structure"); @@ -2542,9 +2552,12 @@ static uint get_table_structure(char *table, char *db, char *table_type, /* Even if the "table" is a view, we do a DROP TABLE here. The view-specific code below fills in the DROP VIEW. + We will skip the DROP TABLE for general_log and slow_log, since + those stmts will fail, in case we apply dump by enabling logging. */ - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", - opt_quoted_table); + if (!general_log_or_slow_log_tables(db, table)) + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", + opt_quoted_table); check_io(sql_file); } @@ -2656,12 +2669,25 @@ static uint get_table_structure(char *table, char *db, char *table_type, row= mysql_fetch_row(result); - fprintf(sql_file, (opt_compatible_mode & 3) ? "%s;\n" : - "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" - "/*!40101 SET character_set_client = utf8 */;\n" - "%s;\n" - "/*!40101 SET character_set_client = @saved_cs_client */;\n", - row[1]); + is_log_table= general_log_or_slow_log_tables(db, table); + if (is_log_table) + row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */ + if (opt_compatible_mode & 3) + { + fprintf(sql_file, + is_log_table ? "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n", + row[1]); + } + else + { + fprintf(sql_file, + "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" + "/*!40101 SET character_set_client = utf8 */;\n" + "%s%s;\n" + "/*!40101 SET character_set_client = @saved_cs_client */;\n", + is_log_table ? "CREATE TABLE IF NOT EXISTS " : "", + row[1]); + } check_io(sql_file); mysql_free_result(result); @@ -4261,6 +4287,22 @@ static int dump_all_tables_in_db(char *database) if (opt_xml) print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS); + if (strcmp(database, "mysql") == 0) + { + char table_type[NAME_LEN]; + char ignore_flag; + uint num_fields; + num_fields= get_table_structure((char *) "general_log", + database, table_type, &ignore_flag); + if (num_fields == 0) + verbose_msg("-- Warning: get_table_structure() failed with some internal " + "error for 'general_log' table\n"); + num_fields= get_table_structure((char *) "slow_log", + database, table_type, &ignore_flag); + if (num_fields == 0) + verbose_msg("-- Warning: get_table_structure() failed with some internal " + "error for 'slow_log' table\n"); + } if (lock_tables) { DYNAMIC_STRING query; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 1d4a5783c3f..fac94e855a4 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -5067,5 +5067,47 @@ RETURN CONCAT(']]]]>, ', s, '!') DROP DATABASE BUG52792; USE test; # +# Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM +# +SET @old_log_output_state= @@global.log_output; +SET @old_general_log_state= @@global.general_log; +SET @old_slow_query_log_state= @@global.slow_query_log; +call mtr.add_suppression("Failed to write to mysql.general_log"); +SET @@global.log_output="TABLE"; +SET @@global.general_log='ON'; +SET @@global.slow_query_log='ON'; +DROP DATABASE mysql; +Warnings: +Error 1146 Table 'mysql.proc' doesn't exist +Error 1146 Table 'mysql.event' doesn't exist +SHOW CREATE TABLE mysql.general_log; +Table Create Table +general_log CREATE TABLE `general_log` ( + `event_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `thread_id` int(11) NOT NULL, + `server_id` int(10) unsigned NOT NULL, + `command_type` varchar(64) NOT NULL, + `argument` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log' +SHOW CREATE TABLE mysql.slow_log; +Table Create Table +slow_log CREATE TABLE `slow_log` ( + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_host` mediumtext NOT NULL, + `query_time` time NOT NULL, + `lock_time` time NOT NULL, + `rows_sent` int(11) NOT NULL, + `rows_examined` int(11) NOT NULL, + `db` varchar(512) NOT NULL, + `last_insert_id` int(11) NOT NULL, + `insert_id` int(11) NOT NULL, + `server_id` int(10) unsigned NOT NULL, + `sql_text` mediumtext NOT NULL +) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log' +SET @@global.log_output= @old_log_output_state; +SET @@global.slow_query_log= @old_slow_query_log_state; +SET @@global.general_log= @old_general_log_state; +# # End of 5.1 tests # diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 20c788e3b9a..7393ca88f0a 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2308,9 +2308,32 @@ DROP DATABASE BUG52792; USE test; +# Wait till we reached the initial number of concurrent sessions +--source include/wait_until_count_sessions.inc + +--echo # +--echo # Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM +--echo # +SET @old_log_output_state= @@global.log_output; +SET @old_general_log_state= @@global.general_log; +SET @old_slow_query_log_state= @@global.slow_query_log; + +call mtr.add_suppression("Failed to write to mysql.general_log"); +--exec $MYSQL_DUMP -uroot --all-databases > $MYSQLTEST_VARDIR/tmp/bug45740.sql +# Make log_output as table and enable general_log and slow_log +SET @@global.log_output="TABLE"; +SET @@global.general_log='ON'; +SET @@global.slow_query_log='ON'; +DROP DATABASE mysql; +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug45740.sql +SHOW CREATE TABLE mysql.general_log; +SHOW CREATE TABLE mysql.slow_log; +--remove_file $MYSQLTEST_VARDIR/tmp/bug45740.sql + +SET @@global.log_output= @old_log_output_state; +SET @@global.slow_query_log= @old_slow_query_log_state; +SET @@global.general_log= @old_general_log_state; + --echo # --echo # End of 5.1 tests --echo # - -# Wait till we reached the initial number of concurrent sessions ---source include/wait_until_count_sessions.inc From 391ea219c21a66e24ea9985ca2581f75bbd7c8f5 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Thu, 10 May 2012 10:18:31 +0530 Subject: [PATCH 32/32] Bug #14007649 65111: INNODB SOMETIMES FAILS TO UPDATE ROWS INSERTED BY A CONCURRENT TRANSACTIO The member function QUICK_RANGE_SELECT::init_ror_merged_scan() performs a table handler clone. Innodb does not provide a clone operation. The ha_innobase::clone() is not there. The handler::clone() does not take care of the ha_innobase->prebuilt->select_lock_type. Because of this what happens is that for one index we do a locking read, and for the other index we were doing a non-locking (consistent) read. The patch introduces ha_innobase::clone() member function. It is implemented similar to ha_myisam::clone(). It calls the base class handler::clone() and then does any additional operation required. I am setting the ha_innobase->prebuilt->select_lock_type correctly. rb://1060 approved by Marko --- .../suite/innodb/r/innodb_bug14007649.result | 56 ++++++++++++++++++ .../suite/innodb/t/innodb_bug14007649.test | 58 +++++++++++++++++++ .../innodb_plugin/r/innodb_bug14007649.result | 56 ++++++++++++++++++ .../innodb_plugin/t/innodb_bug14007649.test | 58 +++++++++++++++++++ storage/innobase/btr/btr0cur.c | 2 + storage/innobase/handler/ha_innodb.cc | 24 ++++++++ storage/innobase/handler/ha_innodb.h | 1 + storage/innodb_plugin/btr/btr0cur.c | 2 + storage/innodb_plugin/handler/ha_innodb.cc | 25 ++++++++ storage/innodb_plugin/handler/ha_innodb.h | 1 + 10 files changed, 283 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb_bug14007649.result create mode 100644 mysql-test/suite/innodb/t/innodb_bug14007649.test create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test diff --git a/mysql-test/suite/innodb/r/innodb_bug14007649.result b/mysql-test/suite/innodb/r/innodb_bug14007649.result new file mode 100644 index 00000000000..1f802dcd146 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug14007649.result @@ -0,0 +1,56 @@ +create table t1 ( +rowid int, +f1 int, +f2 int, +key i1 (f1, f2), +key i2 (f2)) engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `rowid` int(11) DEFAULT NULL, + `f1` int(11) DEFAULT NULL, + `f2` int(11) DEFAULT NULL, + KEY `i1` (`f1`,`f2`), + KEY `i2` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL); +start transaction with consistent snapshot; +start transaction; +update t1 set f2 = 4 where f1 = 1 and f2 is null; +(b) Number of rows updated: +select row_count(); +row_count() +1 +insert into t1 values (3, 1, null); +(b) After update and insert query. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 4 +3 1 NULL +commit; +(a) Before the update statement is executed. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 NULL +SET SESSION debug="+d,bug14007649"; +update t1 set f2 = 6 where f1 = 1 and f2 is null; +(a) Number of rows updated: +select row_count(); +row_count() +1 +(a) After the update statement is executed. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 NULL +3 1 6 +commit; +"The trx with consistent snapshot ended." +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 4 +3 1 6 +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb_bug14007649.test b/mysql-test/suite/innodb/t/innodb_bug14007649.test new file mode 100644 index 00000000000..2832bd41f3c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug14007649.test @@ -0,0 +1,58 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +create table t1 ( + rowid int, + f1 int, + f2 int, + key i1 (f1, f2), + key i2 (f2)) engine=innodb; + +show create table t1; +insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL); + +connect (a,localhost,root,,); +connect (b,localhost,root,,); + +connection a; +start transaction with consistent snapshot; + +connection b; +start transaction; +update t1 set f2 = 4 where f1 = 1 and f2 is null; + +-- echo (b) Number of rows updated: +select row_count(); + +insert into t1 values (3, 1, null); + +-- echo (b) After update and insert query. +select rowid, f1, f2 from t1; + +commit; + +connection a; + +-- echo (a) Before the update statement is executed. +select rowid, f1, f2 from t1; + +SET SESSION debug="+d,bug14007649"; +update t1 set f2 = 6 where f1 = 1 and f2 is null; + +-- echo (a) Number of rows updated: +select row_count(); + +-- echo (a) After the update statement is executed. +select rowid, f1, f2 from t1; + +commit; + +--echo "The trx with consistent snapshot ended." + +select rowid, f1, f2 from t1; + +connection default; +disconnect a; +disconnect b; + +drop table t1; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result b/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result new file mode 100644 index 00000000000..1f802dcd146 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug14007649.result @@ -0,0 +1,56 @@ +create table t1 ( +rowid int, +f1 int, +f2 int, +key i1 (f1, f2), +key i2 (f2)) engine=innodb; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `rowid` int(11) DEFAULT NULL, + `f1` int(11) DEFAULT NULL, + `f2` int(11) DEFAULT NULL, + KEY `i1` (`f1`,`f2`), + KEY `i2` (`f2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL); +start transaction with consistent snapshot; +start transaction; +update t1 set f2 = 4 where f1 = 1 and f2 is null; +(b) Number of rows updated: +select row_count(); +row_count() +1 +insert into t1 values (3, 1, null); +(b) After update and insert query. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 4 +3 1 NULL +commit; +(a) Before the update statement is executed. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 NULL +SET SESSION debug="+d,bug14007649"; +update t1 set f2 = 6 where f1 = 1 and f2 is null; +(a) Number of rows updated: +select row_count(); +row_count() +1 +(a) After the update statement is executed. +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 NULL +3 1 6 +commit; +"The trx with consistent snapshot ended." +select rowid, f1, f2 from t1; +rowid f1 f2 +1 1 10 +2 1 4 +3 1 6 +drop table t1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test b/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test new file mode 100644 index 00000000000..e1d27ecd742 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug14007649.test @@ -0,0 +1,58 @@ +--source include/have_innodb_plugin.inc +--source include/have_debug.inc + +create table t1 ( + rowid int, + f1 int, + f2 int, + key i1 (f1, f2), + key i2 (f2)) engine=innodb; + +show create table t1; +insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL); + +connect (a,localhost,root,,); +connect (b,localhost,root,,); + +connection a; +start transaction with consistent snapshot; + +connection b; +start transaction; +update t1 set f2 = 4 where f1 = 1 and f2 is null; + +-- echo (b) Number of rows updated: +select row_count(); + +insert into t1 values (3, 1, null); + +-- echo (b) After update and insert query. +select rowid, f1, f2 from t1; + +commit; + +connection a; + +-- echo (a) Before the update statement is executed. +select rowid, f1, f2 from t1; + +SET SESSION debug="+d,bug14007649"; +update t1 set f2 = 6 where f1 = 1 and f2 is null; + +-- echo (a) Number of rows updated: +select row_count(); + +-- echo (a) After the update statement is executed. +select rowid, f1, f2 from t1; + +commit; + +--echo "The trx with consistent snapshot ended." + +select rowid, f1, f2 from t1; + +connection default; +disconnect a; +disconnect b; + +drop table t1; diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index c09d6408fa0..4678ea8cd22 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2792,6 +2792,8 @@ btr_estimate_n_rows_in_range( n_rows = n_rows * 2; } + DBUG_EXECUTE_IF("bug14007649", return(n_rows);); + /* Do not estimate the number of rows in the range to over 1 / 2 of the estimated rows in the whole table */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6576016501f..8ed082037f0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3180,6 +3180,30 @@ table_opened: DBUG_RETURN(0); } +handler* +ha_innobase::clone( +/*===============*/ + const char* name, /*!< in: table name */ + MEM_ROOT* mem_root) /*!< in: memory context */ +{ + ha_innobase* new_handler; + + DBUG_ENTER("ha_innobase::clone"); + + new_handler = static_cast(handler::clone(name, + mem_root)); + if (new_handler) { + DBUG_ASSERT(new_handler->prebuilt != NULL); + DBUG_ASSERT(new_handler->user_thd == user_thd); + DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx); + + new_handler->prebuilt->select_lock_type + = prebuilt->select_lock_type; + } + + DBUG_RETURN(new_handler); +} + uint ha_innobase::max_supported_key_part_length() const { diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 8b91f7d4c51..93229ad9185 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -117,6 +117,7 @@ class ha_innobase: public handler const key_map *keys_to_use_for_scanning() { return &key_map_full; } int open(const char *name, int mode, uint test_if_locked); + handler* clone(const char *name, MEM_ROOT *mem_root); int close(void); double scan_time(); double read_time(uint index, uint ranges, ha_rows rows); diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index b67da53ec8a..223b976dea7 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -3194,6 +3194,8 @@ btr_estimate_n_rows_in_range( n_rows = n_rows * 2; } + DBUG_EXECUTE_IF("bug14007649", return(n_rows);); + /* Do not estimate the number of rows in the range to over 1 / 2 of the estimated rows in the whole table */ diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index ca6788999ae..2207f9d009d 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -3889,6 +3889,31 @@ table_opened: DBUG_RETURN(0); } +UNIV_INTERN +handler* +ha_innobase::clone( +/*===============*/ + const char* name, /*!< in: table name */ + MEM_ROOT* mem_root) /*!< in: memory context */ +{ + ha_innobase* new_handler; + + DBUG_ENTER("ha_innobase::clone"); + + new_handler = static_cast(handler::clone(name, + mem_root)); + if (new_handler) { + DBUG_ASSERT(new_handler->prebuilt != NULL); + DBUG_ASSERT(new_handler->user_thd == user_thd); + DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx); + + new_handler->prebuilt->select_lock_type + = prebuilt->select_lock_type; + } + + DBUG_RETURN(new_handler); +} + UNIV_INTERN uint ha_innobase::max_supported_key_part_length() const diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index f7a5456b1a7..15cc4a77b6f 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -132,6 +132,7 @@ class ha_innobase: public handler const key_map* keys_to_use_for_scanning(); int open(const char *name, int mode, uint test_if_locked); + handler* clone(const char *name, MEM_ROOT *mem_root); int close(void); double scan_time(); double read_time(uint index, uint ranges, ha_rows rows);