From b61d6be9fdfa61b7ae8e8436cf1748fc126ec15f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 17 Apr 2012 13:25:41 +0300 Subject: [PATCH 01/55] 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 25f82f8a261963f633ccfdabce27dfc1e0309286 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Wed, 18 Apr 2012 11:25:01 +0530 Subject: [PATCH 02/55] 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 03/55] 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 11b2cf4f03b7c4b84c26d3c95cdf6f8fa6322349 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 18 Apr 2012 13:14:05 +0200 Subject: [PATCH 04/55] 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 05/55] 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 06/55] 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 07/55] 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 08/55] 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 bd0c38064faf52e65ee8d2044f15b6393b44522d Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Mon, 23 Apr 2012 11:51:19 +0300 Subject: [PATCH 09/55] 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 1a2cf649dc411b47122419cb9e8c8ef1a26ae91a Mon Sep 17 00:00:00 2001 From: irana Date: Thu, 26 Apr 2012 08:17:14 -0700 Subject: [PATCH 10/55] 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 11/55] 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 e7364ec29c522b5d98951b851ca3cc62a9f46d59 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Mon, 7 May 2012 16:46:44 +0530 Subject: [PATCH 12/55] 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 13/55] 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); From e72278fd423d98181d1c4da34e8369e7219b05f8 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 15 May 2012 09:14:44 +0200 Subject: [PATCH 14/55] Added some extra optional path to test suites --- mysql-test/lib/My/Find.pm | 7 ++++--- mysql-test/lib/mtr_cases.pm | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/My/Find.pm b/mysql-test/lib/My/Find.pm index 0fffc0d7fd7..2730f83a496 100644 --- a/mysql-test/lib/My/Find.pm +++ b/mysql-test/lib/My/Find.pm @@ -126,9 +126,9 @@ sub my_find_file { # # sub my_find_dir { - my ($base, $paths, $dirs, $required)= @_; - croak "usage: my_find_dir(, [, ])" - unless (@_ == 3 or @_ == 2); + my ($base, $paths, $dirs, $optional)= @_; + croak "usage: my_find_dir(, [, [, ]])" + unless (@_ == 3 or @_ == 2 or @_ == 4); # ------------------------------------------------------- # Find and return the first directory @@ -136,6 +136,7 @@ sub my_find_dir { foreach my $path (my_find_paths($base, $paths, $dirs)) { return $path if ( -d $path ); } + return "" if $optional; find_error($base, $paths, $dirs); } diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 90045d855ab..19eaac6747c 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -127,6 +127,7 @@ sub collect_test_cases ($$$) { { push(@$cases, collect_one_suite($suite, $opt_cases)); last if $some_test_found; + push(@$cases, collect_one_suite("i_".$suite, $opt_cases)); } } @@ -277,10 +278,10 @@ sub collect_one_suite($) $suitedir= my_find_dir($suitedir, ["suite", ".", - # Look in storage engine specific suite dirs - "../storage/*/mysql-test-suites" + "../internal/mysql-test/suite" ], - [$suite]); + [$suite], ($suite =~ /^i_/)); + return unless $suitedir; } mtr_verbose("suitedir: $suitedir"); } From fcb033053d72502366f890c4652603c6cbc4fadb Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 May 2012 13:12:22 +0300 Subject: [PATCH 15/55] Bug #11761822: yassl rejects valid certificate which openssl accepts Applied the fix that updates yaSSL to 2.2.1 and fixes parsing this particular certificate. Added a test case with the certificate itself. --- extra/yassl/taocrypt/src/asn.cpp | 4 ++++ vio/viosslfactories.c | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp index a502666d15b..5ec4cac1c44 100644 --- a/extra/yassl/taocrypt/src/asn.cpp +++ b/extra/yassl/taocrypt/src/asn.cpp @@ -758,6 +758,10 @@ void CertDecoder::GetName(NameType nt) while (source_.get_index() < length) { GetSet(); + if (source_.GetError().What() == SET_E) { + source_.SetError(NO_ERROR_E); // extensions may only have sequence + source_.prev(); + } GetSequence(); byte b = source_.next(); diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 3c0c2f3a7ec..945e288a799 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -201,7 +201,7 @@ static void check_ssl_init() static struct st_VioSSLFd * new_VioSSLFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher, SSL_METHOD *method, + const char *cipher, my_bool is_client_method, enum enum_ssl_init_error* error) { DH *dh; @@ -222,7 +222,9 @@ new_VioSSLFd(const char *key_file, const char *cert_file, my_malloc(sizeof(struct st_VioSSLFd),MYF(0))))) DBUG_RETURN(0); - if (!(ssl_fd->ssl_context= SSL_CTX_new(method))) + if (!(ssl_fd->ssl_context= SSL_CTX_new(is_client_method ? + TLSv1_client_method() : + TLSv1_server_method()))) { *error= SSL_INITERR_MEMFAIL; DBUG_PRINT("error", ("%s", sslGetErrString(*error))); @@ -300,7 +302,7 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, verify= SSL_VERIFY_NONE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_client_method(), &dummy))) + ca_path, cipher, TRUE, &dummy))) { return 0; } @@ -322,7 +324,7 @@ new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_server_method(), error))) + ca_path, cipher, FALSE, error))) { return 0; } From 5917c58a5d23e30ed33ca9559ac3a8010d182d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 15 May 2012 15:04:39 +0300 Subject: [PATCH 16/55] Bug#14025221 FOREIGN KEY REFERENCES FREED MEMORY AFTER DROP INDEX dict_table_replace_index_in_foreign_list(): Replace the dropped index also in the foreign key constraints of child tables that are referencing this table. row_ins_check_foreign_constraint(): If the underlying index is missing, refuse the operation. rb:1051 approved by Jimmy Yang --- storage/innodb_plugin/dict/dict0dict.c | 22 ++++++++++++++++++++++ storage/innodb_plugin/row/row0ins.c | 6 ++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index df7ac85681c..cfeba015723 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -4872,6 +4872,28 @@ dict_table_replace_index_in_foreign_list( foreign->foreign_index = new_index; } } + + + for (foreign = UT_LIST_GET_FIRST(table->referenced_list); + foreign; + foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) { + + dict_index_t* new_index; + + if (foreign->referenced_index == index) { + ut_ad(foreign->referenced_table == index->table); + + new_index = dict_foreign_find_index( + foreign->referenced_table, + foreign->referenced_col_names, + foreign->n_fields, index, + /*check_charsets=*/TRUE, /*check_null=*/FALSE); + ut_ad(new_index || !trx->check_foreigns); + ut_ad(!new_index || new_index->table == index->table); + + foreign->referenced_index = new_index; + } + } } /**********************************************************************//** diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 2d4afa6c5ed..4994a91dd23 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1296,7 +1296,8 @@ run_again: check_index = foreign->foreign_index; } - if (check_table == NULL || check_table->ibd_file_missing) { + if (check_table == NULL || check_table->ibd_file_missing + || check_index == NULL) { if (check_ref) { FILE* ef = dict_foreign_err_file; @@ -1331,9 +1332,6 @@ run_again: goto exit_func; } - ut_a(check_table); - ut_a(check_index); - if (check_table != table) { /* We already have a LOCK_IX on table, but not necessarily on check_table */ From 5d8b38df4c6166bb7f52d6602c2b7eb48628c233 Mon Sep 17 00:00:00 2001 From: Nuno Carvalho Date: Tue, 15 May 2012 22:06:48 +0100 Subject: [PATCH 17/55] BUG#11754117 - 45670: INTVAR_EVENTS FOR FILTERED-OUT QUERY_LOG_EVENTS ARE EXECUTED Improved random number filtering verification on rpl_filter_tables_not_exist test. --- .../rpl/r/rpl_filter_tables_not_exist.result | 9 +++++---- .../rpl/t/rpl_filter_tables_not_exist.test | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) 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..e11c54499fe 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,17 +114,17 @@ 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.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), 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 TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), 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); +INSERT INTO test.t_slave VALUES(NULL, RAND(), @c); SET INSERT_ID=2; SET @c=2; SET @@rand_seed1=10000000, @@rand_seed2=1000000; -INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); +INSERT INTO t5 VALUES (NULL, RAND(), @c); Warnings: Note 1592 Statement may not be safe to log in statement format. SELECT b into @b FROM test.t5; @@ -132,6 +132,7 @@ 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; +include/assert.inc [Random values from master and slave must be different] drop table test.t5; drop table test.t1; drop table test.t_slave; 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 b62a6e96437..3572dd53ea7 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 @@ -215,21 +215,23 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; # be filtered as well. # connection master; -CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); # ignored on slave +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), 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); +# Although RAND() is from 0 to 1.0, DECIMAL(M,D), requires that M must be >= D. +CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b DECIMAL(20,20), 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); + INSERT INTO test.t_slave VALUES(NULL, RAND(), @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 +INSERT INTO t5 VALUES (NULL, RAND(), @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 @@ -253,10 +255,9 @@ if (`SELECT @a != 2 and @c != NULL`) 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. -} +--let $assert_text= Random values from master and slave must be different +--let $assert_cond= $b_master != $b_slave +--source include/assert.inc # cleanup BUG#11754117 connection master; From bcb5d73767fbc04c88d3c8b05eafbdc9a905ea1f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 16 May 2012 11:17:48 +0530 Subject: [PATCH 18/55] Bug #12752572 61579: REPLICATION FAILURE WHILE INNODB_AUTOINC_LOCK_MODE=1 AND USING TRIGGER When an insert stmt like "insert into t values (1),(2),(3)" is executed, the autoincrement values assigned to these three rows are expected to be contiguous. In the given lock mode (innodb_autoinc_lock_mode=1), the auto inc lock will be released before the end of the statement. So to make the autoincrement contiguous for a given statement, we need to reserve the auto inc values at the beginning of the statement. rb://1074 approved by Alexander Nozdrin --- sql/handler.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index d2eaab19ad8..20bf2355c25 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2397,6 +2397,17 @@ int handler::update_auto_increment() reservation means potentially losing unused values). Note that in prelocked mode no estimation is given. */ + + /* + For multi-row inserts, if the bulk inserts cannot be started, the + handler::estimation_rows_to_insert will not be set. Set it here. + */ + if ((estimation_rows_to_insert == 0) && + (thd->lex->many_values.elements > 0)) + { + estimation_rows_to_insert= thd->lex->many_values.elements; + } + if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) nb_desired_values= estimation_rows_to_insert; else /* go with the increasing defaults */ @@ -4690,6 +4701,8 @@ int handler::ha_write_row(uchar *buf) DBUG_RETURN(error); if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) DBUG_RETURN(error); /* purecov: inspected */ + + DEBUG_SYNC_C("ha_write_row_end"); DBUG_RETURN(0); } From 6b05e434bff43365add2a9636edbace157c84e89 Mon Sep 17 00:00:00 2001 From: Venkata Sidagam Date: Wed, 16 May 2012 16:14:27 +0530 Subject: [PATCH 19/55] Bug #13955256: KEYCACHE CRASHES, CORRUPTIONS/HANGS WITH, FULLTEXT INDEX AND CONCURRENT DML. Problem Statement: ------------------ 1) Create a table with FT index. 2) Enable concurrent inserts. 3) In multiple threads do below operations repeatedly a) truncate table b) insert into table .... c) select ... match .. against .. non-boolean/boolean mode After some time we could observe two different assert core dumps Analysis: -------- 1)assert core dump at key_read_cache(): Two select threads operating in-parallel on same key root block. 1st select thread block->status is set to BLOCK_ERROR because the my_pread() in read_block() is returning '0'. Truncate table made the index file size as 1024 and pread was asked to get the block of count bytes(1024 bytes) from offset of 1024 which it cannot read since its "end of file" and retuning '0' setting "my_errno= HA_ERR_FILE_TOO_SHORT" and the key_file_length, key_root[0] is same i.e. 1024. Since block status has BLOCK_ERROR the 1st select thread enter into the free_block() and will be under wait on conditional mutex by making status as BLOCK_REASSIGNED and goes for wait_on_readers(). Other select thread will also work on the same block and sees the status as BLOCK_ERROR and enters into free_block(), checks for BLOCK_REASSIGNED and asserting the server. 2)assert core dump at key_write_cache(): One select thread and One insert thread. Select thread gets the unlocks the 'keycache->cache_lock', which allows other threads to continue and gets the pread() return value as'0'(please see the explanation above) and tries to get the lock on 'keycache->cache_lock' and waits there for the lock. Insert thread requests for the block, block will be assigned from the hash list and makes the page_status as 'PAGE_WAIT_TO_BE_READ' and goes for the read_block(), waits in the queue since there are some other threads performing reads on the same block. Select thread which was waiting for the 'keycache->cache_lock' mutex in the read_block() will continue after getting the my_pread() value as '0' and sets the block status as BLOCK_ERROR and goes to the free_block() and go to the wait_for_readers(). Now the insert thread will awake and continues. and checks block->status as not BLOCK_READ and it asserts. Fix: --- In the full text code, multiple readers of index file is not guarded. Hence added below below code in _ft2_search() and walk_and_match(). to lock the key_root I have used below code in _ft2_search() if (info->s->concurrent_insert) mysql_rwlock_rdlock(&share->key_root_lock[0]); and to unlock if (info->s->concurrent_insert) mysql_rwlock_unlock(&share->key_root_lock[0]); storage/myisam/ft_boolean_search.c: Since its a recursion function, to avoid confusion in taking and releasing the locks, renamed _ft2_search() to _ft2_search_internal() function. And _ft2_search() will take the lock, call _ft2_search_internal() and release the lock in case of concurrent inserts. storage/myisam/ft_nlq_search.c: Added read locks code in walk_and_match() --- storage/myisam/ft_boolean_search.c | 16 ++++++++++++++-- storage/myisam/ft_nlq_search.c | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index 62d912a0fd0..16cf2669c6d 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -354,7 +354,7 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), returns 1 if the search was finished (must-word wasn't found) */ -static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +static int _ft2_search_no_lock(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) { int r; int subkeys=1; @@ -454,7 +454,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) ftbw->key_root=info->s->state.key_root[ftb->keynr]; ftbw->keyinfo=info->s->keyinfo+ftb->keynr; ftbw->off=0; - return _ft2_search(ftb, ftbw, 0); + return _ft2_search_no_lock(ftb, ftbw, 0); } /* matching key found */ @@ -482,6 +482,18 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) return 0; } +static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +{ + int r; + MYISAM_SHARE *share= ftb->info->s; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[ftb->keynr]); + r= _ft2_search_no_lock(ftb, ftbw, init_search); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[ftb->keynr]); + return r; +} + static void _ftb_init_index_search(FT_INFO *ftb) { int i; diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c index 333ec5d0b4f..c74451828a4 100644 --- a/storage/myisam/ft_nlq_search.c +++ b/storage/myisam/ft_nlq_search.c @@ -71,9 +71,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) TREE_ELEMENT *selem; double gweight=1; MI_INFO *info=aio->info; + MYISAM_SHARE *share= info->s; uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; - my_off_t key_root=info->s->state.key_root[aio->keynr]; + my_off_t key_root; uint extra= HA_FT_WLEN + info->s->rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; @@ -89,6 +90,11 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keylen-=HA_FT_WLEN; doc_cnt=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + + key_root= share->state.key_root[aio->keynr]; + /* Skip rows inserted by current inserted */ for (r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root) ; !r && @@ -98,6 +104,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) info->lastkey_length, SEARCH_BIGGER, key_root)) ; + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); + info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ /* The following should be safe, even if we compare doubles */ @@ -121,6 +130,8 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keyinfo=& info->s->ft2_keyinfo; key_root=info->lastpos; keylen=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); r=_mi_search_first(info, keyinfo, key_root); goto do_skip; } @@ -155,6 +166,9 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) if (gweight < 0 || doc_cnt > 2000000) gweight=0; + if (share->concurrent_insert) + rw_rdlock(&share->key_root_lock[aio->keynr]); + if (_mi_test_if_changed(info) == 0) r=_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); @@ -167,6 +181,8 @@ do_skip: r= _mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); + if (share->concurrent_insert) + rw_unlock(&share->key_root_lock[aio->keynr]); } word->weight=gweight; From ce9e6b5a9a8b10ec9b09ea4349c811cdff2ab95f Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Wed, 16 May 2012 16:36:49 +0530 Subject: [PATCH 20/55] Bug #13943231: ALTER TABLE AFTER DISCARD MAY CRASH THE SERVER The following scenario crashes our mysql server: 1. set global innodb_file_per_table=1; 2. create table t1(c1 int) engine=innodb; 3. alter table t1 discard tablespace; 4. alter table t1 add unique index(c1); Step 4 crashes the server. This patch introduces a check on discarded tablespace to avoid the crash. rb://1041 approved by Marko Makela --- storage/innodb_plugin/handler/handler0alter.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index e2702b157af..6f02b500d96 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -665,6 +665,10 @@ ha_innobase::add_index( DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } + if (innodb_table->tablespace_discarded) { + DBUG_RETURN(-1); + } + /* Check that index keys are sensible */ error = innobase_check_index_keys(key_info, num_of_keys, innodb_table); From 932376f97ad4e085926ba39ddc61542561d95ea0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 May 2012 10:15:54 +0530 Subject: [PATCH 21/55] From 3e1758d36a76e1b5c2333b3a137446afb61f80fe Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 May 2012 11:41:46 +0100 Subject: [PATCH 22/55] From 21faded51e8389d72cc1a729a5e40a5e41aa4540 Mon Sep 17 00:00:00 2001 From: Gopal Shankar Date: Thu, 17 May 2012 18:07:59 +0530 Subject: [PATCH 23/55] Bug#12636001 : deadlock from thd_security_context PROBLEM: Threads end-up in deadlock due to locks acquired as described below, con1: Run Query on a table. It is important that this SELECT must back-off while trying to open the t1 and enter into wait_for_condition(). The SELECT then is blocked trying to lock mysys_var->mutex which is held by con3. The very significant fact here is that mysys_var->current_mutex will still point to LOCK_open, even if LOCK_open is no longer held by con1 at this point. con2: Try dropping table used in con1 or query some table. It will hold LOCK_open and be blocked trying to lock kernel_mutex held by con4. con3: Try killing the query run by con1. It will hold THD::LOCK_thd_data belonging to con1 while trying to lock mysys_var->current_mutex belonging to con1. But current_mutex will point to LOCK_open which is held by con2. con4: Get innodb engine status It will hold kernel_mutex, trying to lock THD::LOCK_thd_data belonging to con1 which is held by con3. So while technically only con2, con3 and con4 participate in the deadlock, con1's mysys_var->current_mutex pointing to LOCK_open is a vital component of the deadlock. CYCLE = (THD::LOCK_thd_data -> LOCK_open -> kernel_mutex -> THD::LOCK_thd_data) FIX: LOCK_thd_data has responsibility of protecting, 1) thd->query, thd->query_length 2) VIO 3) thd->mysys_var (used by KILL statement and shutdown) 4) THD during thread delete. Among above responsibilities, 1), 2)and (3,4) seems to be three independent group of responsibility. If there is different LOCK owning responsibility of (3,4), the above mentioned deadlock cycle can be avoid. This fix introduces LOCK_thd_kill to handle responsibility (3,4), which eliminates the deadlock issue. Note: The problem is not found in 5.5. Introduction MDL subsystem caused metadata locking responsibility to be moved from TDC/TC to MDL subsystem. Due to this, responsibility of LOCK_open is reduced. As the use of LOCK_open is removed in open_table() and mysql_rm_table() the above mentioned CYCLE does not form. Revision ID for changes, open_table() = dlenev@mysql.com-20100727133458-m3ua9oslnx8fbbvz mysql_rm_table() = jon.hauglid@oracle.com-20101116100012-kxep9txz2fxy3nmw --- sql/event_scheduler.cc | 4 ++-- sql/slave.cc | 4 ++-- sql/sql_base.cc | 2 ++ sql/sql_class.cc | 13 +++++++++++-- sql/sql_class.h | 16 ++++++++++++++-- sql/sql_parse.cc | 5 +++-- sql/sql_repl.cc | 4 ++-- 7 files changed, 36 insertions(+), 12 deletions(-) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index a24c70a8494..d217d8d76cd 100755 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -632,13 +632,13 @@ Event_scheduler::stop() DBUG_PRINT("info", ("Scheduler thread has id %lu", scheduler_thd->thread_id)); /* Lock from delete */ - pthread_mutex_lock(&scheduler_thd->LOCK_thd_data); + pthread_mutex_lock(&scheduler_thd->LOCK_thd_kill); /* This will wake up the thread if it waits on Queue's conditional */ sql_print_information("Event Scheduler: Killing the scheduler thread, " "thread id %lu", scheduler_thd->thread_id); scheduler_thd->awake(THD::KILL_CONNECTION); - pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data); + pthread_mutex_unlock(&scheduler_thd->LOCK_thd_kill); /* thd could be 0x0, when shutting down */ sql_print_information("Event Scheduler: " diff --git a/sql/slave.cc b/sql/slave.cc index 0910d196583..437762cc318 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -515,7 +515,7 @@ terminate_slave_thread(THD *thd, int error; DBUG_PRINT("loop", ("killing slave thread")); - pthread_mutex_lock(&thd->LOCK_thd_data); + pthread_mutex_lock(&thd->LOCK_thd_kill); #ifndef DONT_USE_THR_ALARM /* Error codes from pthread_kill are: @@ -526,7 +526,7 @@ terminate_slave_thread(THD *thd, DBUG_ASSERT(err != EINVAL); #endif thd->awake(THD::NOT_KILLED); - pthread_mutex_unlock(&thd->LOCK_thd_data); + pthread_mutex_unlock(&thd->LOCK_thd_kill); /* There is a small chance that slave thread might miss the first diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ca24830db63..2ce5ec81917 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2203,6 +2203,8 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) */ pthread_mutex_unlock(mutex); + DEBUG_SYNC(thd, "waiting_for_table_unlock"); + DBUG_EXECUTE_IF("sleep_after_waiting_for_table", my_sleep(1000000);); pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2f3e8153cbd..0f6bd4c1954 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -365,6 +365,7 @@ extern "C" char *thd_security_context(THD *thd, char *buffer, unsigned int length, unsigned int max_query_len) { + DEBUG_SYNC(thd, "thd_security_context"); String str(buffer, length, &my_charset_latin1); const Security_context *sctx= &thd->main_security_ctx; char header[64]; @@ -695,6 +696,7 @@ THD::THD() active_vio = 0; #endif pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&LOCK_thd_kill, MY_MUTEX_INIT_FAST); /* Variables with default values */ proc_info="login"; @@ -999,6 +1001,8 @@ THD::~THD() /* Ensure that no one is using THD */ pthread_mutex_lock(&LOCK_thd_data); pthread_mutex_unlock(&LOCK_thd_data); + pthread_mutex_lock(&LOCK_thd_kill); + pthread_mutex_unlock(&LOCK_thd_kill); add_to_status(&global_status_var, &status_var); /* Close connection */ @@ -1026,6 +1030,7 @@ THD::~THD() #endif mysys_var=0; // Safety (shouldn't be needed) pthread_mutex_destroy(&LOCK_thd_data); + pthread_mutex_destroy(&LOCK_thd_kill); #ifndef DBUG_OFF dbug_sentry= THD_SENTRY_GONE; #endif @@ -1104,9 +1109,11 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, void THD::awake(THD::killed_state state_to_set) { DBUG_ENTER("THD::awake"); - DBUG_PRINT("enter", ("this: 0x%lx", (long) this)); + DBUG_PRINT("enter", ("this: 0x%lx thread_id=%lu killed_state=%d", + (long) this, thread_id, state_to_set)); THD_CHECK_SENTRY(this); - safe_mutex_assert_owner(&LOCK_thd_data); + safe_mutex_assert_not_owner(&LOCK_thd_data); + safe_mutex_assert_owner(&LOCK_thd_kill); killed= state_to_set; if (state_to_set != THD::KILL_QUERY) @@ -1127,7 +1134,9 @@ void THD::awake(THD::killed_state state_to_set) hack is not used. */ + pthread_mutex_lock(&LOCK_thd_data); close_active_vio(); + pthread_mutex_unlock(&LOCK_thd_data); } #endif } diff --git a/sql/sql_class.h b/sql/sql_class.h index 31d2c664aae..3ecf032db71 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1342,11 +1342,23 @@ public: Protects THD data accessed from other threads: - thd->query and thd->query_length (used by SHOW ENGINE INNODB STATUS and SHOW PROCESSLIST - - thd->mysys_var (used by KILL statement and shutdown). - Is locked when THD is deleted. */ pthread_mutex_t LOCK_thd_data; + /** + - Protects thd->mysys_var (used during KILL statement and shutdown). + - Is Locked when THD is deleted. + + Note: This responsibility was earlier handled by LOCK_thd_data. + This lock is introduced to solve a deadlock issue waiting for + LOCK_thd_data. As this lock reduces responsibility of LOCK_thd_data + the deadlock issues is solved. + Caution: LOCK_thd_kill should not be taken while holding LOCK_thd_data. + THD::awake() currently takes LOCK_thd_data after holding + LOCK_thd_kill. + */ + pthread_mutex_t LOCK_thd_kill; + /* all prepared statements and cursors of this connection */ Statement_map stmt_map; /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 729a963eef1..6c376d2c0da 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7187,7 +7187,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) continue; if (tmp->thread_id == id) { - pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -7215,12 +7215,13 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) if ((thd->security_ctx->master_access & SUPER_ACL) || thd->security_ctx->user_matches(tmp->security_ctx)) { + DEBUG_SYNC(thd, "kill_one_thread_before_kill"); tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); error=0; } else error=ER_KILL_DENIED_ERROR; - pthread_mutex_unlock(&tmp->LOCK_thd_data); + pthread_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); DBUG_RETURN(error); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index b985805a827..c92d2db2c1e 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1133,7 +1133,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) if (tmp->command == COM_BINLOG_DUMP && tmp->server_id == slave_server_id) { - pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -1146,7 +1146,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id) again. We just to do kill the thread ourselves. */ tmp->awake(THD::KILL_QUERY); - pthread_mutex_unlock(&tmp->LOCK_thd_data); + pthread_mutex_unlock(&tmp->LOCK_thd_kill); } } From 781137c0dddc3c9315a8d40e579fe82f6a900d61 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Fri, 18 May 2012 14:44:40 +0530 Subject: [PATCH 24/55] BUG#14005409 - 64624 Problem: After the fix for Bug#12589870, a new field that stores the length of db name was added in the buffer that stores the query to be executed. Unlike for the plain user session, the replication execution did not allocate the necessary chunk in Query-event constructor. This caused an invalid read while accessing this field. Solution: We fix this problem by allocating a necessary chunk in the buffer created in the Query_log_event::Query_log_event() and store the length of database name. sql/log_event.cc: Added a new field in the buffer created in the Query_log_event's constructor and store the length of database name. --- sql/log_event.cc | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 8606964113c..afcc283a6d1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2835,24 +2835,34 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, pos= (const uchar*) end; // Break loop } } - + + /** + Layout for the data buffer is as follows + +--------+-----------+------+------+---------+----+-------+ + | catlog | time_zone | user | host | db name | \0 | Query | + +--------+-----------+------+------+---------+----+-------+ + + To support the query cache we append the following buffer to the above + +-------+----------------------------------------+-------+ + |db len | uninitiatlized space of size of db len | FLAGS | + +-------+----------------------------------------+-------+ + + The area of buffer starting from Query field all the way to the end belongs + to the Query buffer and its structure is described in alloc_query() in + sql_parse.cc + */ + + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + user.length + 1 + + host.length + 1 + + data_len + 1 #if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1 + - QUERY_CACHE_FLAGS_SIZE + - user.length + 1 + - host.length + 1 + - db_len + 1, - MYF(MY_WME)))) -#else - if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + - time_zone_len + 1 + - data_len + 1 + - user.length + 1 + - host.length + 1, - MYF(MY_WME)))) + + sizeof(size_t)//for db_len + + db_len + 1 + + QUERY_CACHE_FLAGS_SIZE #endif + , MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { @@ -2891,6 +2901,14 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db= (char *)start; query= (char *)(start + db_len + 1); q_len= data_len - db_len -1; + /** + Append the db length at the end of the buffer. This will be used by + Query_cache::send_result_to_client() in case the query cache is On. + */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) + size_t db_length= (size_t)db_len; + memcpy(start + data_len + 1, &db_length, sizeof(size_t)); +#endif DBUG_VOID_RETURN; } From 1605b7f68f30038ea0a9ce16e688f5827057f64f Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Mon, 21 May 2012 12:57:39 +0530 Subject: [PATCH 25/55] BUG#12400221 - 60926: BINARY LOG EVENTS LARGER THAN MAX_ALLOWED_PACKET Problem ======== SQL statements close to the size of max_allowed_packet produce binary log events larger than max_allowed_packet. The reason why this failure is occuring is because the event length is more than the total size of the max_allowed_packet + max_event_header length. Now since the event length exceeds this size master Dump thread is unable to send the packet on to the slave. That can happen e.g with row-based replication in Update_rows event. Fix ==== The problem was fixed by increasing the max_allowed_packet for the slave's threads (IO/SQL) by increasing it to 1GB. This is done using the new server option included which is used to regulate the max_allowed_packet of the slave thread (IO/SQL). This causes the large packets to be received by the slave and apply it successfully. sql/log_event.h: Added the new option in the log_event.h file. sql/mysqld.cc: Added a new option to the server. sql/slave.cc: Increasing the session max_allowed_packet to a large value , i.e. not taking global(max_allowed) into consideration, for the slave's threads. --- mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 11 +- mysql-test/suite/rpl/t/rpl_packet-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_packet.test | 11 +- .../inc/slave_max_allowed_packet_basic.inc | 177 ++++++++++++++++++ .../r/max_allowed_packet_basic.result | 12 ++ .../sys_vars/r/max_allowed_packet_func.result | 2 + .../sys_vars/r/net_buffer_length_basic.result | 2 + .../t/slave_max_allowed_packet_basic.test | 3 + sql/log_event.cc | 2 +- sql/log_event.h | 7 + sql/mysql_priv.h | 1 + sql/mysqld.cc | 7 + sql/set_var.cc | 2 + sql/share/errmsg.txt | 34 ++-- sql/slave.cc | 11 +- sql/sql_repl.cc | 2 +- 17 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc create mode 100644 mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 91d307008f0..b2224dcd725 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -9,7 +9,7 @@ change master to master_log_pos=MASTER_LOG_POS; Read_Master_Log_Pos = '75' start slave; include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event'' include/stop_slave_sql.inc show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 7a7f8141ac8..6d68a094594 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -1,7 +1,7 @@ include/master-slave.inc [connection master] -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; SET @@global.max_allowed_packet=1024; @@ -30,14 +30,14 @@ include/start_slave.inc CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); include/wait_for_slave_io_error.inc [errno=1153] -Last_IO_Error = 'Got a packet bigger than 'max_allowed_packet' bytes' +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' include/stop_slave_sql.inc include/rpl_reset.inc DROP TABLE t1; CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); -include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'' +include/wait_for_slave_io_error.inc [errno=1153] +Last_IO_Error = 'Got a packet bigger than 'slave_max_allowed_packet' bytes' STOP SLAVE; RESET SLAVE; RESET MASTER; @@ -52,6 +52,7 @@ SET @@global.max_allowed_packet= 1024; Warnings: Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length= 1024; +SET @@global.slave_max_allowed_packet= 1073741824; DROP TABLE t1; RESET SLAVE; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_packet-slave.opt b/mysql-test/suite/rpl/t/rpl_packet-slave.opt index 42d4f94c999..e0a7a203f99 100644 --- a/mysql-test/suite/rpl/t/rpl_packet-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_packet-slave.opt @@ -1 +1 @@ --O max_allowed_packet=1024 -O net_buffer_length=1024 +-O max_allowed_packet=1024 -O net_buffer_length=1024 -O slave_max_allowed_packet=1024 diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 3197b6160cd..7fbea87f71e 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -11,9 +11,8 @@ # max-out size db name source include/master-slave.inc; source include/have_binlog_format_row.inc; -call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); -call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); - +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'slave_max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Log entry on master is longer than slave_max_allowed_packet"); let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; eval drop database if exists $db; @@ -23,6 +22,7 @@ eval create database $db; connection master; let $old_max_allowed_packet= `SELECT @@global.max_allowed_packet`; let $old_net_buffer_length= `SELECT @@global.net_buffer_length`; +let $old_slave_max_allowed_packet= `SELECT @@global.slave_max_allowed_packet`; SET @@global.max_allowed_packet=1024; SET @@global.net_buffer_length=1024; @@ -124,8 +124,8 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), R connection slave; # The slave I/O thread must stop after receiving -# 1236=ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. ---let $slave_io_errno= 1236 +# 1153 = ER_NET_PACKET_TOO_LARGE +--let $slave_io_errno= 1153 --let $show_slave_io_error= 1 --source include/wait_for_slave_io_error.inc @@ -166,6 +166,7 @@ connection master; DROP TABLE t1; eval SET @@global.max_allowed_packet= $old_max_allowed_packet; eval SET @@global.net_buffer_length= $old_net_buffer_length; +eval SET @@global.slave_max_allowed_packet= $old_slave_max_allowed_packet; # slave is stopped connection slave; DROP TABLE t1; diff --git a/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc new file mode 100644 index 00000000000..4caaae84906 --- /dev/null +++ b/mysql-test/suite/sys_vars/inc/slave_max_allowed_packet_basic.inc @@ -0,0 +1,177 @@ +############## mysql-test\t\slave_max_allowed_packet_basic.test ################## +# # +# Variable Name: slave_max_allowed_packet # +# Scope: GLOBAL # +# Access Type: Dynamic # +# Data Type: numeric # +# Default Value:1073741824 # +# Range: 1024 - 1073741824 # +# # +# # +# # +# Description: Test Cases of Dynamic System Variable slave_max_allowed_packet # +# that checks the behavior of this variable in the following ways# +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +############################################################################### + +--source include/load_sysvars.inc + +######################################################################## +# START OF slave_max_allowed_packet TESTS # +######################################################################## + + +########################################################################### +# Saving initial value of slave_max_allowed_packet in a temporary variable# +########################################################################### + +SET @start_value = @@global.slave_max_allowed_packet; +SELECT @start_value; + + +--echo '#--------------------FN_DYNVARS_072_01------------------------#' +######################################################################## +# Display the DEFAULT value of slave_max_allowed_packet # +######################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SET @@global.slave_max_allowed_packet = DEFAULT; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_02-------------------------#' +############################################### +# Verify default value of variable # +############################################### + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet = 1073741824; +--echo 'Bug# 34876: Incorrect Default Value is assigned to variable'; + +--echo '#--------------------FN_DYNVARS_072_03------------------------#' +######################################################################## +# Change the value of slave_max_allowed_packet to a valid value # +######################################################################## + +SET @@global.slave_max_allowed_packet = 1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1073741824; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1025; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 65535; +SELECT @@global.slave_max_allowed_packet; +--echo 'Bug# 34877: Invalid Values are coming in variable on assigning valid values'; + + +--echo '#--------------------FN_DYNVARS_072_04-------------------------#' +########################################################################### +# Change the value of slave_max_allowed_packet to invalid value # +########################################################################### + +SET @@global.slave_max_allowed_packet = -1; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 100000000000; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 10000.01; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = -1024; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 4294967296; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = 1023; +SELECT @@global.slave_max_allowed_packet; + +--echo 'Bug # 34837: Errors are not coming on assigning invalid values to variable'; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = ON; +SELECT @@global.slave_max_allowed_packet; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.slave_max_allowed_packet = 'test'; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#-------------------FN_DYNVARS_072_05----------------------------#' +########################################################################### +# Test if accessing session slave_max_allowed_packet gives error # +########################################################################### + +--Error ER_GLOBAL_VARIABLE +SET @@session.slave_max_allowed_packet = 4096; +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.slave_max_allowed_packet; + + +--echo '#----------------------FN_DYNVARS_072_06------------------------#' +############################################################################## +# Check if the value in GLOBAL & SESSION Tables matches values in variable # +############################################################################## + +SELECT @@global.slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + +SELECT @@slave_max_allowed_packet = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.SESSION_VARIABLES +WHERE VARIABLE_NAME='slave_max_allowed_packet'; + + +--echo '#---------------------FN_DYNVARS_072_07----------------------#' +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### + +SET @@global.slave_max_allowed_packet = TRUE; +SELECT @@global.slave_max_allowed_packet; +SET @@global.slave_max_allowed_packet = FALSE; +SELECT @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_08----------------------#' +######################################################################################################## +# Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable # +######################################################################################################## + +SET @@global.slave_max_allowed_packet = 5000; +SELECT @@slave_max_allowed_packet = @@global.slave_max_allowed_packet; + + +--echo '#---------------------FN_DYNVARS_072_09----------------------#' +################################################################################ +# Check if slave_max_allowed_packet can be accessed with and without @@ sign # +################################################################################ + +--Error ER_GLOBAL_VARIABLE +SET slave_max_allowed_packet = 6000; +SELECT @@slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET local.slave_max_allowed_packet = 7000; +--Error ER_UNKNOWN_TABLE +SELECT local.slave_max_allowed_packet; +--Error ER_PARSE_ERROR +SET global.slave_max_allowed_packet = 8000; +--Error ER_UNKNOWN_TABLE +SELECT global.slave_max_allowed_packet; +--Error ER_BAD_FIELD_ERROR +SELECT slave_max_allowed_packet = @@session.slave_max_allowed_packet; + + +############################## +# Restore initial value # +############################## + +SET @@global.slave_max_allowed_packet = @start_value; +SELECT @@global.slave_max_allowed_packet; + + +######################################################################## +# END OF slave_max_allowed_packet TESTS # +######################################################################## diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result index ca5b87f19cb..810ddb00b79 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_basic.result @@ -7,6 +7,7 @@ SET @@global.max_allowed_packet = DEFAULT; SET @@global.max_allowed_packet = 1000; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1000' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.max_allowed_packet = DEFAULT; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet @@ -25,10 +26,14 @@ SELECT @@global.max_allowed_packet = 1048576; 1 '#--------------------FN_DYNVARS_070_03-------------------------#' SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1025; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -71,18 +76,21 @@ SELECT @@session.max_allowed_packet; SET @@global.max_allowed_packet = 0; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = -1024; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '-1024' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = 1023; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1023' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 @@ -146,17 +154,21 @@ WHERE VARIABLE_NAME='max_allowed_packet'; SET @@global.max_allowed_packet = TRUE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '1' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 SET @@global.max_allowed_packet = FALSE; Warnings: Warning 1292 Truncated incorrect max_allowed_packet value: '0' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.max_allowed_packet; @@global.max_allowed_packet 1024 '#---------------------FN_DYNVARS_070_09----------------------#' SET @@global.max_allowed_packet = 2048; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@max_allowed_packet = @@global.max_allowed_packet; @@max_allowed_packet = @@global.max_allowed_packet 0 diff --git a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result index 0d682b65aea..a202701b60f 100644 --- a/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result +++ b/mysql-test/suite/sys_vars/r/max_allowed_packet_func.result @@ -23,6 +23,8 @@ SELECT @@session.net_buffer_length; '#--------------------FN_DYNVARS_070_02-------------------------#' ## Setting value of max_allowed packet and net_buffer_length to 1024 ## SET @@global.max_allowed_packet = 1024; +Warnings: +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SET @@global.net_buffer_length = 1024; SELECT @@global.max_allowed_packet; @@global.max_allowed_packet diff --git a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result index 07f933b5a4b..026c883e501 100644 --- a/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result +++ b/mysql-test/suite/sys_vars/r/net_buffer_length_basic.result @@ -63,12 +63,14 @@ SELECT @@global.net_buffer_length; SET @@global.net_buffer_length = 1048577; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '1048577' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 SET @@global.net_buffer_length = 104857633; Warnings: Warning 1292 Truncated incorrect net_buffer_length value: '104857633' +Warning 1105 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length' SELECT @@global.net_buffer_length; @@global.net_buffer_length 1048576 diff --git a/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test new file mode 100644 index 00000000000..5b6a557738b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/slave_max_allowed_packet_basic.test @@ -0,0 +1,3 @@ +--source suite/sys_vars/inc/slave_max_allowed_packet_basic.inc + + diff --git a/sql/log_event.cc b/sql/log_event.cc index afcc283a6d1..958b7e4ef36 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1122,7 +1122,7 @@ failed my_b_read")); Log_event *res= 0; #ifndef max_allowed_packet THD *thd=current_thd; - uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0; + uint max_allowed_packet= thd ? slave_max_allowed_packet:~(ulong)0; #endif if (data_len > max_allowed_packet) diff --git a/sql/log_event.h b/sql/log_event.h index 4c80148458c..39cd55f313e 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -275,6 +275,13 @@ struct sql_ex_info MAX_SIZE_LOG_EVENT_STATUS + /* status */ \ NAME_LEN + 1) +/* + The new option is added to handle large packets that are sent from the master + to the slave. It is used to increase the thd(max_allowed) for both the + DUMP thread on the master and the SQL/IO thread on the slave. +*/ +#define MAX_MAX_ALLOWED_PACKET 1024*1024*1024 + /* Event header offsets; these point to places inside the fixed header. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 359e84a3370..937617032dd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1944,6 +1944,7 @@ extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; extern ulong query_buff_size; +extern ulong slave_max_allowed_packet; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, open_files_limit; extern ulonglong max_binlog_cache_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4a80fd043c8..db73504cb17 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -28,6 +28,7 @@ #include "mysys_err.h" #include "events.h" #include "debug_sync.h" +#include "log_event.h" #include "../storage/myisam/ha_myisam.h" @@ -574,6 +575,7 @@ static const char *slave_exec_mode_str= "STRICT"; ulong thread_cache_size=0, thread_pool_size= 0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; +ulong slave_max_allowed_packet= 0; ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; @@ -5572,6 +5574,7 @@ enum options_mysqld OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD, OPT_LONG_QUERY_TIME, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, + OPT_SLAVE_MAX_ALLOWED_PACKET, OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE, OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS, OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE, @@ -6700,6 +6703,10 @@ thread is in the relay logs.", &global_system_variables.max_allowed_packet, &max_system_variables.max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, + {"slave_max_allowed_packet", OPT_SLAVE_MAX_ALLOWED_PACKET, + "The maximum packet length to sent successfully from the master to slave.", + &slave_max_allowed_packet, &slave_max_allowed_packet, 0, GET_ULONG, + REQUIRED_ARG, MAX_MAX_ALLOWED_PACKET, 1024, MAX_MAX_ALLOWED_PACKET, MALLOC_OVERHEAD, 1024, 0}, {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index d9133a25d98..bbc47c2d7e8 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -366,6 +366,8 @@ static sys_var_const sys_lower_case_table_names(&vars, static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet", &SV::max_allowed_packet, check_max_allowed_packet); +static sys_var_long_ptr sys_slave_max_allowed_packet(&vars, "slave_max_allowed_packet", + &slave_max_allowed_packet); static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size", &max_binlog_cache_size); static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size", diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7cb9d9ebcc1..99bae298e49 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -3512,23 +3512,23 @@ ER_ABORTING_CONNECTION 08S01 swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)" ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s' (%-.64s)" ER_NET_PACKET_TOO_LARGE 08S01 - cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'" - dan "Modtog en datapakke som var større end 'max_allowed_packet'" - nla "Groter pakket ontvangen dan 'max_allowed_packet'" - eng "Got a packet bigger than 'max_allowed_packet' bytes" - est "Saabus suurem pakett kui lubatud 'max_allowed_packet' muutujaga" - fre "Paquet plus grand que 'max_allowed_packet' reçu" - ger "Empfangenes Paket ist größer als 'max_allowed_packet' Bytes" - hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'max_allowed_packet'" - ita "Ricevuto un pacchetto piu` grande di 'max_allowed_packet'" - kor "'max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." - por "Obteve um pacote maior do que a taxa máxima de pacotes definida (max_allowed_packet)" - rum "Un packet mai mare decit 'max_allowed_packet' a fost primit" - rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'max_allowed_packet'" - serbian "Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'" - spa "Obtenido un paquete mayor que 'max_allowed_packet'" - swe "Kommunkationspaketet är större än 'max_allowed_packet'" - ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö max_allowed_packet" + cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'slave_max_allowed_packet'" + dan "Modtog en datapakke som var større end 'slave_max_allowed_packet'" + nla "Groter pakket ontvangen dan 'slave_max_allowed_packet'" + eng "Got a packet bigger than 'slave_max_allowed_packet' bytes" + est "Saabus suurem pakett kui lubatud 'slave_max_allowed_packet' muutujaga" + fre "Paquet plus grand que 'slave_max_allowed_packet' reçu" + ger "Empfangenes Paket ist größer als 'slave_max_allowed_packet' Bytes" + hun "A kapott csomag nagyobb, mint a maximalisan engedelyezett: 'slave_max_allowed_packet'" + ita "Ricevuto un pacchetto piu` grande di 'slave_max_allowed_packet'" + kor "'slave_max_allowed_packet'º¸´Ù ´õÅ« ÆÐŶÀ» ¹Þ¾Ò½À´Ï´Ù." + por "Obteve um pacote maior do que a taxa máxima de pacotes definida (slave_max_allowed_packet)" + rum "Un packet mai mare decit 'slave_max_allowed_packet' a fost primit" + rus "ðÏÌÕÞÅÎÎÙÊ ÐÁËÅÔ ÂÏÌØÛÅ, ÞÅÍ 'slave_max_allowed_packet'" + serbian "Primio sam mrežni paket veæi od definisane vrednosti 'slave_max_allowed_packet'" + spa "Obtenido un paquete mayor que 'slave_max_allowed_packet'" + swe "Kommunkationspaketet är större än 'slave_max_allowed_packet'" + ukr "ïÔÒÉÍÁÎÏ ÐÁËÅÔ Â¦ÌØÛÉÊ Î¦Ö slave_max_allowed_packet" ER_NET_READ_ERROR_FROM_PIPE 08S01 cze "Zji-B¹tìna chyba pøi ètení z roury spojení" dan "Fik læsefejl fra forbindelse (connection pipe)" diff --git a/sql/slave.cc b/sql/slave.cc index 437762cc318..b555d4351c9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1884,8 +1884,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) slave threads, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet - + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ + thd->variables.max_allowed_packet= slave_max_allowed_packet; + thd->net.max_packet_size= slave_max_allowed_packet; thd->slave_thread = 1; thd->enable_slow_log= opt_log_slow_slave_statements; set_slave_thread_options(thd); @@ -2630,6 +2630,7 @@ pthread_handler_t handle_slave_io(void *arg) thread, since a replication event can become this much larger than the corresponding packet (query) sent from client to master. */ + thd->net.max_packet_size= slave_max_allowed_packet; mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER; } else @@ -2761,10 +2762,10 @@ reading event")) switch (mysql_error_number) { case CR_NET_PACKET_TOO_LARGE: sql_print_error("\ -Log entry on master is longer than max_allowed_packet (%ld) on \ +Log entry on master is longer than slave_max_allowed_packet (%lu) on \ slave. If the entry is correct, restart the server with a higher value of \ -max_allowed_packet", - thd->variables.max_allowed_packet); +slave_max_allowed_packet", + slave_max_allowed_packet); mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, "%s", ER(ER_NET_PACKET_TOO_LARGE)); goto err; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c92d2db2c1e..e3188def206 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -469,7 +469,7 @@ impossible position"; this larger than the corresponding packet (query) sent from client to master. */ - thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER; + thd->variables.max_allowed_packet= ULONG_MAX; /* We can set log_lock now, it does not move (it's a member of From e979417c06f98f8ca81a7442d93f53d9aec79446 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Mon, 21 May 2012 17:25:40 +0530 Subject: [PATCH 26/55] Bug #12752572 61579: REPLICATION FAILURE WHILE INNODB_AUTOINC_LOCK_MODE=1 AND USING TRIGGER When an insert stmt like "insert into t values (1),(2),(3)" is executed, the autoincrement values assigned to these three rows are expected to be contiguous. In the given lock mode (innodb_autoinc_lock_mode=1), the auto inc lock will be released before the end of the statement. So to make the autoincrement contiguous for a given statement, we need to reserve the auto inc values at the beginning of the statement. Modified the fix based on review comment by Svoj. --- sql/handler.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 20bf2355c25..9e43d5aba93 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2398,18 +2398,18 @@ int handler::update_auto_increment() Note that in prelocked mode no estimation is given. */ - /* - For multi-row inserts, if the bulk inserts cannot be started, the - handler::estimation_rows_to_insert will not be set. Set it here. - */ - if ((estimation_rows_to_insert == 0) && - (thd->lex->many_values.elements > 0)) - { - estimation_rows_to_insert= thd->lex->many_values.elements; - } - if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) nb_desired_values= estimation_rows_to_insert; + else if ((auto_inc_intervals_count == 0) && + (thd->lex->many_values.elements > 0)) + { + /* + For multi-row inserts, if the bulk inserts cannot be started, the + handler::estimation_rows_to_insert will not be set. But we still + want to reserve the autoinc values. + */ + nb_desired_values= thd->lex->many_values.elements; + } else /* go with the increasing defaults */ { /* avoid overflow in formula, with this if() */ From 01748ce128ae4c29cfb63e88cd68918e7d48e946 Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Thu, 24 May 2012 12:37:03 -0400 Subject: [PATCH 27/55] Bug #14100254 65389: MVCC IS BROKEN WITH IMPLICIT LOCK rb://1088 approved by: Marko Makela This bug was introduced in early stages of plugin. We were not checking for an implicit lock on sec index rec for trx_id that is stamped on current version of the clust_index in case where the clust_index has a previous delete marked version. --- storage/innodb_plugin/row/row0vers.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/storage/innodb_plugin/row/row0vers.c b/storage/innodb_plugin/row/row0vers.c index 8a7bb842293..9aeaa2db6c0 100644 --- a/storage/innodb_plugin/row/row0vers.c +++ b/storage/innodb_plugin/row/row0vers.c @@ -208,18 +208,6 @@ row_vers_impl_x_locked_off_kernel( vers_del = rec_get_deleted_flag(prev_version, comp); prev_trx_id = row_get_rec_trx_id(prev_version, clust_index, clust_offsets); - - /* If the trx_id and prev_trx_id are different and if - the prev_version is marked deleted then the - prev_trx_id must have already committed for the trx_id - to be able to modify the row. Therefore, prev_trx_id - cannot hold any implicit lock. */ - if (vers_del && 0 != ut_dulint_cmp(trx_id, prev_trx_id)) { - - mutex_enter(&kernel_mutex); - break; - } - /* The stack of versions is locked by mtr. Thus, it is safe to fetch the prefixes for externally stored columns. */ From d8b2d4a0694156848db0862a230d248653f8ebe5 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 29 May 2012 12:11:30 +0530 Subject: [PATCH 28/55] Bug#11762667: MYSQLBINLOG IGNORES ERRORS WHILE WRITING OUTPUT Problem: mysqlbinlog exits without any error code in case of file write error. It is because of the fact that the calls to Log_event::print() method does not return a value and the thus any error were being ignored. Resolution: We resolve this problem by checking for the IO_CACHE::error == -1 after every call to Log_event:: print() and terminating the further execution. client/mysqlbinlog.cc: - handled error conditions during event->print() calls - added check for error in end_io_cache() mysys/my_write.c: Added debug code to simulate file write error. error returned will be ENOSPC=> error no space on the disk sql/log_event.cc: Added debug code to simulate file write error, by reducing the size of io cache. --- client/mysqlbinlog.cc | 21 ++++++++++++++++++++- mysys/my_write.c | 12 +++++++++++- sql/log_event.cc | 6 ++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index db48675ade2..dd09e7a0938 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -690,6 +690,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, DBUG_ENTER("process_event"); print_event_info->short_form= short_form; Exit_status retval= OK_CONTINUE; + IO_CACHE *const head= &print_event_info->head_cache; /* Format events are not concerned by --offset and such, we always need to @@ -753,6 +754,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } else ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; break; case CREATE_FILE_EVENT: @@ -804,6 +807,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, output of Append_block_log_event::print is only a comment. */ ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if ((retval= load_processor.process((Append_block_log_event*) ev)) != OK_CONTINUE) goto end; @@ -812,6 +817,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, case EXEC_LOAD_EVENT: { ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; Execute_load_log_event *exv= (Execute_load_log_event*)ev; Create_file_log_event *ce= load_processor.grab_event(exv->file_id); /* @@ -841,6 +848,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, print_event_info->common_header_len= glob_description_event->common_header_len; ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if (!remote_opt) ev->free_temp_buf(); // free memory allocated in dump_local_log_entries else @@ -864,6 +873,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, break; case BEGIN_LOAD_QUERY_EVENT: ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; if ((retval= load_processor.process((Begin_load_query_log_event*) ev)) != OK_CONTINUE) goto end; @@ -974,6 +985,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } default: ev->print(result_file, print_event_info); + if (head->error == -1) + goto err; } } @@ -2012,7 +2025,13 @@ err: end: if (fd >= 0) my_close(fd, MYF(MY_WME)); - end_io_cache(file); + /* + Since the end_io_cache() writes to the + file errors may happen. + */ + if (end_io_cache(file)) + retval= ERROR_STOP; + return retval; } diff --git a/mysys/my_write.c b/mysys/my_write.c index f261c768dcb..b545ab776b0 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -38,7 +38,17 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags) for (;;) { - if ((writenbytes= write(Filedes, Buffer, Count)) == Count) + writenbytes= write(Filedes, Buffer, Count); + /** + To simulate the write error set the errno = error code + and the number pf written bytes to -1. + */ + DBUG_EXECUTE_IF ("simulate_file_write_error", + { + errno= ENOSPC; + writenbytes= (size_t) -1; + }); + if (writenbytes == Count) break; if (writenbytes != (size_t) -1) { /* Safeguard */ diff --git a/sql/log_event.cc b/sql/log_event.cc index afcc283a6d1..e7c3419c34f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3090,6 +3090,12 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) { Write_on_release_cache cache(&print_event_info->head_cache, file); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_write(). + */ + DBUG_EXECUTE_IF ("simulate_file_write_error", + {(&cache)->write_pos= (&cache)->write_end- 500;}); print_query_header(&cache, print_event_info); my_b_write(&cache, (uchar*) query, q_len); my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); From 96eb519eb77b078f9f96935aacaded44e20ed95c Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Wed, 30 May 2012 13:54:15 +0530 Subject: [PATCH 29/55] Fixing the build failure on Windows debug build. --- sql/log_event.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index e7c3419c34f..a79797e4bc9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2852,17 +2852,24 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, sql_parse.cc */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + time_zone_len + 1 + user.length + 1 + host.length + 1 + data_len + 1 -#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE) - + sizeof(size_t)//for db_len - + db_len + 1 - + QUERY_CACHE_FLAGS_SIZE + + sizeof(size_t)//for db_len + + db_len + 1 + + QUERY_CACHE_FLAGS_SIZE, + MYF(MY_WME)))) +#else + if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + user.length + 1 + + host.length + 1 + + data_len + 1, + MYF(MY_WME)))) #endif - , MYF(MY_WME)))) DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { From f8a6521789eadeebc64c3001a1d5f04ef3c31a2e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 May 2012 14:00:29 +0530 Subject: [PATCH 30/55] From 70d01f5182429751171b71246ef0e3fea30667af Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 May 2012 14:32:29 +0530 Subject: [PATCH 31/55] From 2ebd927ec0ba2de6219dc23a01c3988273302b3e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 May 2012 22:28:18 +0530 Subject: [PATCH 32/55] From a28a2ca798e8a4912cf1b91b6e71eaa0a9fb8bb7 Mon Sep 17 00:00:00 2001 From: Annamalai Gurusami Date: Fri, 1 Jun 2012 14:12:57 +0530 Subject: [PATCH 33/55] Bug #13933132: [ERROR] GOT ERROR -1 WHEN READING TABLE APPEARED WHEN KILLING Suppose there is a query waiting for a lock. If the user kills this query, then "Got error -1 when reading table" error message must not be logged in the server log file. Since this is a user requested interruption, no spurious error message must be logged in the server log. This patch will remove the error message from the log. approved by joh and tatjana --- sql/sql_select.cc | 3 ++- storage/innobase/handler/ha_innodb.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1cf52e88c12..7c3d2de22bc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11791,7 +11791,8 @@ int report_error(TABLE *table, int error) Locking reads can legally return also these errors, do not print them to the .err log */ - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT + && !table->in_use->killed) sql_print_error("Got error %d when reading table '%s'", error, table->s->path.str); table->file->print_error(error,MYF(0)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8ed082037f0..51b7007145c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4893,6 +4893,7 @@ ha_innobase::index_read( ulint ret; DBUG_ENTER("index_read"); + DEBUG_SYNC_C("ha_innobase_index_read_begin"); ut_a(prebuilt->trx == thd_to_trx(user_thd)); ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT); From 2b085e1fba410ceaea2585c9cff511a9cfd2f7ae Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 5 Jun 2012 15:53:39 +0200 Subject: [PATCH 34/55] Bug#14051002 VALGRIND: CONDITIONAL JUMP OR MOVE IN RR_CMP / MY_QSORT Patch for 5.1 and 5.5: fix typo in byte comparison in rr_cmp() --- sql/records.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/records.cc b/sql/records.cc index e275db83c93..da876f7554c 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -631,7 +631,7 @@ static int rr_cmp(uchar *a,uchar *b) if (a[4] != b[4]) return (int) a[4] - (int) b[4]; if (a[5] != b[5]) - return (int) a[1] - (int) b[5]; + return (int) a[5] - (int) b[5]; if (a[6] != b[6]) return (int) a[6] - (int) b[6]; return (int) a[7] - (int) b[7]; From cf37a481f0114d4cdb40c4d8fb483939f6b1bc5a Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Wed, 13 Jun 2012 16:03:58 +0530 Subject: [PATCH 35/55] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Issue : Sequence of calling inc_host_errors() and reset_host_errors() required some changes in order to maintain correct connection error count. Solution : Call to reset_host_errors() is shifted to a location after which no calls to inc_host_errors() are made. --- sql/hostname.cc | 9 ++++++++ sql/sql_connect.cc | 54 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 9796755e9fb..38316a8ee19 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,6 +214,15 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else + + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + const char* fake_host= "santa.claus.ipv4.example.com"; + name=my_strdup(fake_host, MYF(0)); + add_hostname(in,name); + DBUG_RETURN(name); + };); + VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 21e2701d06c..7a934541d53 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,7 +360,6 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { - inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -832,6 +831,19 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } + /* BEGIN : DEBUG */ + DBUG_EXECUTE_IF("addr_fake_ipv4", + { + struct sockaddr *sa= (sockaddr *) &net->vio->remote; + sa->sa_family= AF_INET; + struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; + /* See RFC 5737, 192.0.2.0/23 is reserved */ + const char* fake= "192.0.2.4"; + ip4->s_addr= inet_addr(fake); + strcpy(ip, fake); + };); + /* END : DEBUG */ + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -935,8 +947,6 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif - if (connect_errors) - reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -953,6 +963,10 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ + DBUG_EXECUTE_IF("host_error_packet_length", + { + bytes_remaining_in_packet= 0; + };); if (bytes_remaining_in_packet < 2) goto error; @@ -1011,6 +1025,10 @@ static int check_connection(THD *thd) skip_to_ssl: + DBUG_EXECUTE_IF("host_error_charset", + { + goto error; + };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1079,6 +1097,10 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } + DBUG_EXECUTE_IF("host_error_SSL_layering", + { + packet_has_required_size= 0; + };); if (!packet_has_required_size) goto error; } @@ -1104,6 +1126,11 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); + DBUG_EXECUTE_IF("host_error_user", + { + user= NULL; + };); + if (user == NULL) goto error; @@ -1131,6 +1158,11 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } + DBUG_EXECUTE_IF("host_error_password", + { + passwd= NULL; + };); + if (passwd == NULL) goto error; @@ -1191,7 +1223,21 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); + + if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) + { + /* + Call to reset_host_errors() should be made only when all sanity checks + are done and connection is going to be a successful. + */ + reset_host_errors(&thd->remote.sin_addr); + return 0; + } + else + { + inc_host_errors(&thd->remote.sin_addr); + return 1; + } error: inc_host_errors(&thd->remote.sin_addr); From 775293b898aa6c5239b17de5d489768de5287803 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Jun 2012 17:07:49 +0530 Subject: [PATCH 36/55] BUG #13946716: FEDERATED_PLUGIN TEST CASE FAIL ON 64BIT ARCHITECTURES --- mysql-test/mysql-test-run.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 294dcf13615..674abe7e102 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1969,6 +1969,7 @@ sub environment_setup { my $lib_example_plugin= mtr_file_exists(vs_config_dirs('storage/example',$plugin_filename), "$basedir/storage/example/.libs/".$plugin_filename, + "$basedir/lib64/mysql/plugin/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename); $ENV{'EXAMPLE_PLUGIN'}= ($lib_example_plugin ? basename($lib_example_plugin) : ""); @@ -1991,6 +1992,7 @@ sub environment_setup { my $lib_fed_plugin= mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), "$basedir/storage/federated/.libs/".$fedplug_filename, + "$basedir/lib64/mysql/plugin/".$fedplug_filename, "$basedir/lib/mysql/plugin/".$fedplug_filename); $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; From bc42eaf95283f66788a70acbed1d7368c784a9a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Jun 2012 13:31:27 +0200 Subject: [PATCH 37/55] Raise version number after cloning 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 84295a15f4a..4e7a3303353 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.64], [], [mysql]) +AC_INIT([MySQL Server], [5.1.65], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From cac1cd88abc2a610b42b89e5d39029f75a760ec4 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Mon, 18 Jun 2012 09:20:12 +0200 Subject: [PATCH 38/55] Bug#13003736 CRASH IN ITEM_REF::WALK WITH SUBQUERIES Problem: Some queries with subqueries and a HAVING clause that consists only of a column not in the select or grouping lists causes the server to crash. During parsing, an Item_ref is constructed for the HAVING column. The name of the column is resolved when JOIN::prepare calls fix_fields() on its having clause. Since the column is not mentioned in the select or grouping lists, a ref pointer is not found and a new Item_field is created instead. The Item_ref is replaced by the Item_field in the tree of HAVING clauses. Since the tree consists only of this item, the pointer that is updated is JOIN::having. However, st_select_lex::having still points to the Item_ref as the root of the tree of HAVING clauses. The bug is triggered when doing filesort for create_sort_index(). When find_all_keys() calls select->cond->walk() it eventually reaches Item_subselect::walk() where it continues to walk the having clauses from lex->having. This means that it finds the Item_ref instead of the new Item_field, and Item_ref::walk() tries to dereference the ref pointer, which is still null. The crash is reproducible only in 5.5, but the problem lies latent in 5.1 and trunk as well. Fix: After calling fix_fields on the having clause in JOIN::prepare(), set select_lex::having to point to the same item as JOIN::having. This patch also fixes a bug in 5.1 and 5.5 that is triggered if the query is executed as a prepared statement. The Item_field is created in the runtime arena when the query is prepared, and the pointer to the item is saved by st_select_lex::fix_prepare_information() and brought back as a dangling pointer when the query is executed, after the runtime arena has been reclaimed. Fix: Backport fix from trunk that switches to the permanent arena before calling Item_ref::fix_fields() in JOIN::prepare(). sql/item.cc: Set context when creating Item_field. sql/sql_select.cc: Switch to permanent arena and update select_lex->having. --- sql/item.cc | 2 +- sql/sql_select.cc | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index 90bfb0d2852..356fe4827c8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6010,7 +6010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (from_field != not_found_field) { Item_field* fld; - if (!(fld= new Item_field(from_field))) + if (!(fld= new Item_field(thd, last_checked_context, from_field))) goto error; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last_checked_context->select_lex, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c3d2de22bc..f2007f609e0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -528,6 +528,8 @@ JOIN::prepare(Item ***rref_pointer_array, if (having) { + Query_arena backup, *arena; + arena= thd->activate_stmt_arena_if_needed(&backup); nesting_map save_allow_sum_func= thd->lex->allow_sum_func; thd->where="having clause"; thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level; @@ -536,6 +538,10 @@ JOIN::prepare(Item ***rref_pointer_array, (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; + select_lex->having= having; + if (arena) + thd->restore_active_arena(arena, &backup); + if (having_fix_rc || thd->is_error()) DBUG_RETURN(-1); /* purecov: inspected */ thd->lex->allow_sum_func= save_allow_sum_func; From 61e428eb846e820ba0764932d1604859e53abe52 Mon Sep 17 00:00:00 2001 From: Harin Vadodaria Date: Tue, 19 Jun 2012 12:56:40 +0530 Subject: [PATCH 39/55] Bug#11753779: MAX_CONNECT_ERRORS WORKS ONLY WHEN 1ST INC_HOST_ERRORS() IS CALLED. Description: Reverting patch 3755 for bug#11753779 --- sql/hostname.cc | 9 -------- sql/sql_connect.cc | 54 ++++------------------------------------------ 2 files changed, 4 insertions(+), 59 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 38316a8ee19..9796755e9fb 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -214,15 +214,6 @@ char * ip_to_hostname(struct in_addr *in, uint *errors) } my_gethostbyname_r_free(); #else - - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - const char* fake_host= "santa.claus.ipv4.example.com"; - name=my_strdup(fake_host, MYF(0)); - add_hostname(in,name); - DBUG_RETURN(name); - };); - VOID(pthread_mutex_lock(&LOCK_hostname)); if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET))) { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 7a934541d53..21e2701d06c 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -360,6 +360,7 @@ check_user(THD *thd, enum enum_server_command command, if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { + inc_host_errors(&thd->remote.sin_addr); my_error(ER_HANDSHAKE_ERROR, MYF(0)); DBUG_RETURN(1); } @@ -831,19 +832,6 @@ static int check_connection(THD *thd) my_error(ER_BAD_HOST_ERROR, MYF(0)); return 1; } - /* BEGIN : DEBUG */ - DBUG_EXECUTE_IF("addr_fake_ipv4", - { - struct sockaddr *sa= (sockaddr *) &net->vio->remote; - sa->sa_family= AF_INET; - struct in_addr *ip4= &((struct sockaddr_in *)sa)->sin_addr; - /* See RFC 5737, 192.0.2.0/23 is reserved */ - const char* fake= "192.0.2.4"; - ip4->s_addr= inet_addr(fake); - strcpy(ip, fake); - };); - /* END : DEBUG */ - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; @@ -947,6 +935,8 @@ static int check_connection(THD *thd) #ifdef _CUSTOMCONFIG_ #include "_cust_sql_parse.h" #endif + if (connect_errors) + reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ @@ -963,10 +953,6 @@ static int check_connection(THD *thd) Peek ahead on the client capability packet and determine which version of the protocol should be used. */ - DBUG_EXECUTE_IF("host_error_packet_length", - { - bytes_remaining_in_packet= 0; - };); if (bytes_remaining_in_packet < 2) goto error; @@ -1025,10 +1011,6 @@ static int check_connection(THD *thd) skip_to_ssl: - DBUG_EXECUTE_IF("host_error_charset", - { - goto error; - };); DBUG_PRINT("info", ("client_character_set: %u", charset_code)); if (thd_init_client_charset(thd, charset_code)) goto error; @@ -1097,10 +1079,6 @@ skip_to_ssl: bytes_remaining_in_packet -= AUTH_PACKET_HEADER_SIZE_PROTO_40; } - DBUG_EXECUTE_IF("host_error_SSL_layering", - { - packet_has_required_size= 0; - };); if (!packet_has_required_size) goto error; } @@ -1126,11 +1104,6 @@ skip_to_ssl: get_string= get_40_protocol_string; user= get_string(&end, &bytes_remaining_in_packet, &user_len); - DBUG_EXECUTE_IF("host_error_user", - { - user= NULL; - };); - if (user == NULL) goto error; @@ -1158,11 +1131,6 @@ skip_to_ssl: passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len); } - DBUG_EXECUTE_IF("host_error_password", - { - passwd= NULL; - };); - if (passwd == NULL) goto error; @@ -1223,21 +1191,7 @@ skip_to_ssl: if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) return 1; /* The error is set by my_strdup(). */ - - if (!check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE)) - { - /* - Call to reset_host_errors() should be made only when all sanity checks - are done and connection is going to be a successful. - */ - reset_host_errors(&thd->remote.sin_addr); - return 0; - } - else - { - inc_host_errors(&thd->remote.sin_addr); - return 1; - } + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); error: inc_host_errors(&thd->remote.sin_addr); From 983fcfaf62fbd4169afd0a3e6182ea46705fa3f5 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Wed, 20 Jun 2012 13:10:13 +0200 Subject: [PATCH 40/55] Version for this release build is 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4e7a3303353..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.65], [], [mysql]) +AC_INIT([MySQL Server], [5.1.64], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 5c724f7b9430bb3794f6e12709268ce5502104e5 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 21 Jun 2012 16:26:50 +0200 Subject: [PATCH 41/55] Fixing wrong comment syntax (discovered by Kent) --- sql/rpl_utility.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* 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); From 5f86ecbf362bc32ec86d7118288b305af74e2fb3 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Tue, 26 Jun 2012 16:30:15 +0200 Subject: [PATCH 42/55] Solve a linkage problem with "libmysqld" on several Solaris platforms: a multiple definition of 'THD::clear_error()' in (at least) libmysqld.a(lib_sql.o) and libmysqld.a(libfederated_a-ha_federated.o). Patch provided by Ramil Kalimullin. --- libmysqld/lib_sql.cc | 6 ------ sql/sql_class.h | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 4afe02efbdb..18b8383406a 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -756,12 +756,6 @@ void THD::clear_data_list() cur_data= 0; } -void THD::clear_error() -{ - if (main_da.is_error()) - main_da.reset_diagnostics_area(); -} - static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 3ecf032db71..5cdb005b517 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2089,7 +2089,6 @@ public: void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); int send_explain_fields(select_result *result); -#ifndef EMBEDDED_LIBRARY /** Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we @@ -2105,9 +2104,9 @@ public: is_slave_error= 0; DBUG_VOID_RETURN; } +#ifndef EMBEDDED_LIBRARY inline bool vio_ok() const { return net.vio != 0; } #else - void clear_error(); inline bool vio_ok() const { return true; } #endif /** From 767501fb54f19adf3c136e5131daf11e34b3f039 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 12:55:45 +0400 Subject: [PATCH 43/55] Backport of the deprecation warning from WL#6219: "Deprecate and remove YEAR(2) type" Print the warning(note): YEAR(x) is deprecated and will be removed in a future release. Please use YEAR(4) instead on "CREATE TABLE ... YEAR(x)" or "ALTER TABLE MODIFY ... YEAR(x)", where x != 4 --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/type_blob.result | 4 ++++ mysql-test/r/type_year.result | 15 +++++++++++++++ .../suite/engines/iuds/r/delete_year.result | 6 ++++++ .../suite/engines/iuds/r/insert_year.result | 12 ++++++++++++ .../suite/engines/iuds/r/update_year.result | 6 ++++++ mysql-test/suite/funcs_1/r/innodb_views.result | 4 ++++ .../suite/funcs_1/r/is_columns_innodb.result | 6 ++++++ .../suite/funcs_1/r/is_columns_memory.result | 6 ++++++ .../suite/funcs_1/r/is_columns_myisam.result | 6 ++++++ .../r/is_columns_myisam_embedded.result | 6 ++++++ mysql-test/suite/funcs_1/r/memory_views.result | 4 ++++ .../suite/funcs_1/r/myisam_views-big.result | 4 ++++ mysql-test/suite/funcs_1/r/ndb_views.result | 4 ++++ mysql-test/suite/funcs_1/r/storedproc.result | 4 ++++ .../innodb_plugin/r/innodb_bug52745.result | 1 + mysql-test/t/type_year.test | 8 ++++++++ sql/field.cc | 11 +++++++++++ sql/sql_yacc.yy | 18 +++++++++++++++++- 19 files changed, 126 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index b90eb2a4c0f..74899a22636 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1524,6 +1524,8 @@ DROP TABLE t1; # Bug#43668: Wrong comparison and MIN/MAX for YEAR(2) # create table t1 (f1 year(2), f2 year(4), f3 date, f4 datetime); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (98,1998,19980101,"1998-01-01 00:00:00"), (00,2000,20000101,"2000-01-01 00:00:01"), diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index e6fd49b4247..8b4b6438842 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -878,6 +878,8 @@ ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT CREATE TABLE b15776 (a char(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(4294967295)); +Warnings: +Note 1287 'YEAR(4294967295)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO b15776 VALUES (42); SELECT * FROM b15776; a @@ -886,6 +888,8 @@ DROP TABLE b15776; CREATE TABLE b15776 (a year(4294967296)); ERROR 42000: Display width out of range for column 'a' (max = 4294967295) CREATE TABLE b15776 (a year(0)); +Warnings: +Note 1287 'YEAR(0)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP TABLE b15776; CREATE TABLE b15776 (a year(-2)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-2))' at line 1 diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result index 2dc491c6166..e00569c93c1 100644 --- a/mysql-test/r/type_year.result +++ b/mysql-test/r/type_year.result @@ -1,5 +1,7 @@ drop table if exists t1; create table t1 (y year,y2 year(2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead insert into t1 values (0,0),(1999,1999),(2000,2000),(2001,2001),(70,70),(69,69); select * from t1; y y2 @@ -50,6 +52,8 @@ End of 5.0 tests # Bug #49480: WHERE using YEAR columns returns unexpected results # CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); INSERT INTO t4 (c4) SELECT c2 FROM t2; @@ -355,4 +359,15 @@ total_rows min_value MAX(c1) 3 0 2155 DROP TABLE t1; # +# WL#6219: Deprecate and remove YEAR(2) type +# +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/suite/engines/iuds/r/delete_year.result b/mysql-test/suite/engines/iuds/r/delete_year.result index 02cbe24ecc9..c82f0dae7d9 100644 --- a/mysql-test/suite/engines/iuds/r/delete_year.result +++ b/mysql-test/suite/engines/iuds/r/delete_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/engines/iuds/r/insert_year.result b/mysql-test/suite/engines/iuds/r/insert_year.result index 386c8090434..b9618ba4e2d 100644 --- a/mysql-test/suite/engines/iuds/r/insert_year.result +++ b/mysql-test/suite/engines/iuds/r/insert_year.result @@ -3235,9 +3235,21 @@ c1 c2 c3 c4 1999 1999 1998-12-30 1998-12-30 11:30:45 DROP TABLE t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1), UNIQUE INDEX(c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t2(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, PRIMARY KEY(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t3(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME, UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2) NOT NULL, c2 YEAR(2) NULL, c3 DATE, c4 DATETIME); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t2 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); INSERT INTO t3 VALUES('1901','1901','98-12-31','98.12.31 11:30:45'),('1999','1999','98-12-30','98.12.30 11:30:45'),('2000','2000','98-12-29','98.12.29 11:30:45'),('2001','2001','98-12-28','98.12.28 11:30:45'),('2099','2099','98-12-27','98.12.27 11:30:45'),('2100','2100','98-12-26','98.12.26 11:30:45'),('2155','2155','98-12-26','98.12.26 11:30:45'); diff --git a/mysql-test/suite/engines/iuds/r/update_year.result b/mysql-test/suite/engines/iuds/r/update_year.result index 1b0ead45314..c762d70a276 100644 --- a/mysql-test/suite/engines/iuds/r/update_year.result +++ b/mysql-test/suite/engines/iuds/r/update_year.result @@ -2,7 +2,13 @@ DROP TABLE IF EXISTS t1,t2,t3,t4; CREATE TABLE t1(c1 YEAR NOT NULL,c2 YEAR, PRIMARY KEY(c1)); CREATE TABLE t2(c1 YEAR NOT NULL, c2 YEAR, UNIQUE INDEX idx(c1,c2)); CREATE TABLE t3(c1 YEAR(2) NOT NULL,c2 YEAR(2), PRIMARY KEY(c1)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CREATE TABLE t4(c1 YEAR(2), c2 YEAR(2), UNIQUE INDEX idx(c1,c2)); +Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead INSERT INTO t1 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t2 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); INSERT INTO t3 VALUES (1901,1901),(1970,1970),(1999,1999),(2000,2000),(2155,2155); diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index a335e135a4f..951068e3300 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_innodb.result b/mysql-test/suite/funcs_1/r/is_columns_innodb.result index 61079b06666..0abe8e11cf3 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_innodb.result +++ b/mysql-test/suite/funcs_1/r/is_columns_innodb.result @@ -132,6 +132,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -262,6 +264,8 @@ f239 varchar(20000) binary, f240 varchar(2000), f241 char(100) ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb4.txt' into table tb4; USE test1; @@ -319,6 +323,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = innodb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/innodb_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_memory.result b/mysql-test/suite/funcs_1/r/is_columns_memory.result index 60dea25e0e3..c476b930f60 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_memory.result +++ b/mysql-test/suite/funcs_1/r/is_columns_memory.result @@ -128,6 +128,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; drop table if exists tb3; @@ -251,6 +253,8 @@ f238 varchar(25000) binary, f239 varbinary(0), f240 varchar(1200) ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb4.txt' into table tb4; USE test1; @@ -308,6 +312,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam.result b/mysql-test/suite/funcs_1/r/is_columns_myisam.result index 6d0a44d2223..0e464d0fbc1 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result index 739f62e371a..7424ba8573d 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result @@ -144,6 +144,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; drop table if exists tb3 ; @@ -283,6 +285,8 @@ f240 varchar(120), f241 char(100), f242 bit(30) ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb4.txt' into table tb4; USE test1; @@ -348,6 +352,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index ccbd086b71f..0bb03e62192 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -54,6 +54,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -113,6 +115,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = memory; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/memory_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 9b07a0ae45b..0afb1d7d6c8 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -62,6 +62,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; DROP DATABASE IF EXISTS test1; @@ -129,6 +131,8 @@ f115 VARBINARY(27) null , f116 VARBINARY(64) null, f117 VARBINARY(192) null ) engine = myisam; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/myisam_tb2.txt' into table tb2; USE test; diff --git a/mysql-test/suite/funcs_1/r/ndb_views.result b/mysql-test/suite/funcs_1/r/ndb_views.result index b75f4955986..17eaedce56b 100644 --- a/mysql-test/suite/funcs_1/r/ndb_views.result +++ b/mysql-test/suite/funcs_1/r/ndb_views.result @@ -53,6 +53,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; DROP DATABASE IF EXISTS test1; @@ -112,6 +114,8 @@ f107 year(4) not null default 2000, f108 enum("1enum","2enum") not null default "1enum", f109 set("1set","2set") not null default "1set" ) engine = ndb; +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead load data infile '/std_data/funcs_1/ndb_tb2.txt' into table tb2 ; USE test; diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result index 8da7213bded..7647579820a 100644 --- a/mysql-test/suite/funcs_1/r/storedproc.result +++ b/mysql-test/suite/funcs_1/r/storedproc.result @@ -7526,9 +7526,13 @@ BEGIN declare x, y, z year(3) default 2005; SELECT x, y, z; END// +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead CALL sp1(); x y z 2005 2005 2005 +Warnings: +Note 1287 'YEAR(3)' is deprecated and will be removed in a future release. Please use YEAR(4) instead DROP PROCEDURE IF EXISTS sp1; CREATE PROCEDURE sp1( ) BEGIN diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result index 74db8b0c20a..927ba0e0e53 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result @@ -58,6 +58,7 @@ col89 float unsigned zerofill DEFAULT NULL, col90 tinyblob ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; Warnings: +Note 1287 'YEAR(2)' is deprecated and will be removed in a future release. Please use YEAR(4) instead Note 1291 Column 'col82' has duplicated value '' in ENUM Note 1291 Column 'col82' has duplicated value '' in ENUM INSERT INTO bug52745 SET diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index 1a9e66478e1..8ba8260cfc4 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -159,6 +159,14 @@ SELECT * FROM t1; SELECT COUNT(*) AS total_rows, MIN(c1) AS min_value, MAX(c1) FROM t1; DROP TABLE t1; +--echo # +--echo # WL#6219: Deprecate and remove YEAR(2) type +--echo # + +CREATE TABLE t1 (c1 YEAR(2), c2 YEAR(4)); +ALTER TABLE t1 MODIFY COLUMN c2 YEAR(2); +DROP TABLE t1; + --echo # --echo End of 5.1 tests diff --git a/sql/field.cc b/sql/field.cc index f398642fdb0..1c937755c0c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10227,6 +10227,17 @@ Create_field::Create_field(Field *old_field,Field *orig_field) geom_type= ((Field_geom*)old_field)->geom_type; break; #endif + case MYSQL_TYPE_YEAR: + if (length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + break; default: break; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e7ff7e91ca..854ba432362 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5034,7 +5034,23 @@ type: $$= MYSQL_TYPE_VARCHAR; } | YEAR_SYM opt_field_length field_options - { $$=MYSQL_TYPE_YEAR; } + { + if (Lex->length) + { + errno= 0; + ulong length= strtoul(Lex->length, NULL, 10); + if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + } + $$=MYSQL_TYPE_YEAR; + } | DATE_SYM { $$=MYSQL_TYPE_DATE; } | TIME_SYM From 1ede2dd8146254951493081f2297b0832fdd4d13 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 29 Jun 2012 13:25:57 +0200 Subject: [PATCH 44/55] Bug#14238406 NEW COMPILATION WARNINGS WITH GCC 4.7 (-WERROR=NARROWING) This patch fixes various compilation warnings of the type "error: narrowing conversion of 'x' from 'datatype1' to 'datatype2' --- client/mysqlbinlog.cc | 4 ++-- include/my_getopt.h | 4 ++-- sql/log.h | 6 ++--- sql/mysqld.cc | 27 +++++++++++----------- sql/sql_profile.cc | 6 ++--- storage/innobase/handler/ha_innodb.cc | 8 +++---- storage/innodb_plugin/handler/ha_innodb.cc | 12 +++++----- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index dd09e7a0938..e7840865a58 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, 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 @@ -1149,7 +1149,7 @@ static struct my_option my_long_options[] = "Stop reading the binlog at position N. Applies to the last binlog " "passed on the command line.", &stop_position, &stop_position, 0, GET_ULL, - REQUIRED_ARG, (ulonglong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, + REQUIRED_ARG, (longlong)(~(my_off_t)0), BIN_LOG_HEADER_SIZE, (ulonglong)(~(my_off_t)0), 0, 0, 0}, {"to-last-log", 't', "Requires -R. Will not stop at the end of the \ requested binlog but rather continue printing until the end of the last \ diff --git a/include/my_getopt.h b/include/my_getopt.h index 8112303a6a5..5824518a085 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2012, 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 @@ -54,7 +54,7 @@ struct my_option enum get_opt_arg_type arg_type; longlong def_value; /* Default value */ longlong min_value; /* Min allowed value */ - longlong max_value; /* Max allowed value */ + ulonglong max_value; /* Max allowed value */ longlong sub_size; /* Subtract this from given value */ long block_size; /* Value should be a mult. of this */ void *app_type; /* To be used by an application */ diff --git a/sql/log.h b/sql/log.h index 9ed5db04e87..02721f1ddd0 100644 --- a/sql/log.h +++ b/sql/log.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2012, 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 @@ -294,8 +294,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG int new_file_impl(bool need_lock); public: - MYSQL_LOG::generate_name; - MYSQL_LOG::is_open; + using MYSQL_LOG::generate_name; + using MYSQL_LOG::is_open; /* This is relay log */ bool is_relay_log; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index db73504cb17..d6397280e0d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, 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 @@ -6710,7 +6710,7 @@ thread is in the relay logs.", {"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE, "Can be used to restrict the total size used to cache a multi-transaction query.", &max_binlog_cache_size, &max_binlog_cache_size, 0, - GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, + GET_ULL, REQUIRED_ARG, (longlong) ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0}, {"max_binlog_size", OPT_MAX_BINLOG_SIZE, "Binary log will be rotated automatically when the size exceeds this " "value. Will also apply to relay logs if max_relay_log_size is 0. " @@ -6748,7 +6748,7 @@ thread is in the relay logs.", "Joins that are probably going to read more than max_join_size records return an error.", &global_system_variables.max_join_size, &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, - HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, + (longlong) HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0}, {"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA, "Max number of bytes in sorted records.", &global_system_variables.max_length_for_sort_data, @@ -6775,7 +6775,7 @@ thread is in the relay logs.", "Limit assumed max number of seeks when looking up rows based on a key.", &global_system_variables.max_seeks_for_key, &max_system_variables.max_seeks_for_key, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the " "first max_sort_length bytes of each value are used; the rest are ignored).", @@ -6799,7 +6799,7 @@ thread is in the relay logs.", {"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT, "After this many write locks, allow some read locks to run in between.", &max_write_lock_count, &max_write_lock_count, 0, GET_ULONG, - REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, + REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0}, {"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT, "Don't log queries which examine less than min_examined_row_limit rows to file.", &global_system_variables.min_examined_row_limit, @@ -6826,18 +6826,19 @@ thread is in the relay logs.", &global_system_variables.myisam_max_extra_sort_file_size, &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32, - 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, + 0, MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, "Don't use the fast sort index method to created index if the temporary " "file would get bigger than this.", &global_system_variables.myisam_max_sort_file_size, &max_system_variables.myisam_max_sort_file_size, 0, - GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, + GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, MAX_FILE_SIZE, 0, 1024*1024, 0}, {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE, "Can be used to restrict the total memory used for memory mmaping of myisam files", &myisam_mmap_size, &myisam_mmap_size, 0, - GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, + GET_ULL, REQUIRED_ARG, (longlong) SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, + 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, "Specifies whether several threads should be used when repairing MyISAM " "tables. For values > 1, one thread is used per index. The value of 1 " @@ -6850,7 +6851,7 @@ thread is in the relay logs.", "or when creating indexes with CREATE INDEX or ALTER TABLE.", &global_system_variables.myisam_sort_buff_size, &max_system_variables.myisam_sort_buff_size, 0, - GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0ULL, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", &opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, @@ -6953,7 +6954,7 @@ thread is in the relay logs.", {"query_cache_size", OPT_QUERY_CACHE_SIZE, "The memory allocated to store results from old queries.", &query_cache_size, &query_cache_size, 0, GET_ULONG, - REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0}, + REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_type", OPT_QUERY_CACHE_TYPE, "0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results " @@ -7015,7 +7016,7 @@ thread is in the relay logs.", "Maximum space to use for all relay logs.", &relay_log_space_limit, &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, - (longlong) ULONG_MAX, 0, 1, 0}, + ULONG_MAX, 0, 1, 0}, {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, "Use compression on master/slave protocol.", &opt_slave_compressed_protocol, @@ -7030,7 +7031,7 @@ thread is in the relay logs.", "it failed with a deadlock or elapsed lock wait timeout, " "before giving up and stopping.", &slave_trans_retries, &slave_trans_retries, 0, - GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 10L, 0L, ULONG_MAX, 0, 1, 0}, #endif /* HAVE_REPLICATION */ {"slow_launch_time", OPT_SLOW_LAUNCH_TIME, "If creating the thread takes longer than this value (in seconds), " @@ -7041,7 +7042,7 @@ thread is in the relay logs.", "Each thread that needs to do a sort allocates a buffer of this size.", &global_system_variables.sortbuff_size, &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG, - MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, + MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0ULL, MALLOC_OVERHEAD, 1, 0}, {"sync-binlog", OPT_SYNC_BINLOG, "Synchronously flush binary log to disk after every #th event. " diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1a6477e4c4d..49666dde476 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2007, 2012, 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 @@ -84,8 +84,8 @@ ST_FIELD_INFO query_profile_statistics_info[]= int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) { - int profile_options = thd->lex->profile_options; - int fields_include_condition_truth_values[]= { + uint profile_options = thd->lex->profile_options; + uint fields_include_condition_truth_values[]= { FALSE, /* Query_id */ FALSE, /* Seq */ TRUE, /* Status */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 51b7007145c..796f51d737b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9128,7 +9128,7 @@ static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -9182,7 +9182,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -9227,7 +9227,7 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes", - NULL, NULL, 20L, 0L, ~0L, 0); + NULL, NULL, 20L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -9237,7 +9237,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 2207f9d009d..412346e8349 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -10974,7 +10974,7 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, PLUGIN_VAR_RQCMDARG, "Number of IOPs the server can do. Tunes the background IO rate", - NULL, NULL, 200, 100, ~0L, 0); + NULL, NULL, 200, 100, ~0UL, 0); static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown, PLUGIN_VAR_OPCMDARG, @@ -11052,7 +11052,7 @@ static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing, static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag, PLUGIN_VAR_RQCMDARG, "Desired maximum length of the purge queue (0 = no limit)", - NULL, NULL, 0, 0, ~0L, 0); + NULL, NULL, 0, 0, ~0UL, 0); static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, @@ -11109,7 +11109,7 @@ static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, PLUGIN_VAR_RQCMDARG, "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket", - NULL, NULL, 500L, 1L, ~0L, 0); + NULL, NULL, 500L, 1L, ~0UL, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, @@ -11171,12 +11171,12 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, PLUGIN_VAR_RQCMDARG, "Count of spin-loop rounds in InnoDB mutexes (30 by default)", - NULL, NULL, 30L, 0L, ~0L, 0); + NULL, NULL, 30L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay, PLUGIN_VAR_OPCMDARG, "Maximum delay between polling for a spin lock (6 by default)", - NULL, NULL, 6L, 0L, ~0L, 0); + NULL, NULL, 6L, 0L, ~0UL, 0); static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, PLUGIN_VAR_RQCMDARG, @@ -11186,7 +11186,7 @@ static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay, PLUGIN_VAR_RQCMDARG, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep", - NULL, NULL, 10000L, 0L, ~0L, 0); + NULL, NULL, 10000L, 0L, ~0UL, 0); static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, From 107c894a540d147338ab4e737eb9ef76e49c3493 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 28 Jun 2012 18:38:55 +0300 Subject: [PATCH 45/55] Bug #13708485: malformed resultset packet crashes client Several fixes : * sql-common/client.c Added a validity check of the fields metadata packet sent by the server. Now libmysql will check if the length of the data sent by the server matches what's expected by the protocol before using the data. * client/mysqltest.cc Fixed the error handling code in mysqltest to avoid sending new commands when the reading the result set failed (and there are unread data in the pipe). * sql_common.h + libmysql/libmysql.c + sql-common/client.c unpack_fields() now generates a proper error when it fails. Added a new argument to this function to support the error generation. * sql/protocol.cc Added a debug trigger to cause the server to send a NULL insted of the packet expected by the client for testing purposes. --- client/mysqltest.cc | 4 +++- include/sql_common.h | 8 +++++--- libmysql/libmysql.c | 8 ++++---- sql-common/client.c | 15 ++++++++++++--- sql/protocol.cc | 4 +++- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 593bb8ea290..e595493ccf0 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2012, 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 @@ -6848,6 +6848,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, */ if ((counter==0) && mysql_read_query_result(mysql)) { + /* we've failed to collect the result set */ + cn->pending= TRUE; handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; diff --git a/include/sql_common.h b/include/sql_common.h index 9e43d076ba9..b64277ce7e1 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2003-2004, 2006 MySQL AB +/* + Copyright (c) 2003, 2012, 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 @@ -23,8 +24,9 @@ extern "C" { #endif extern CHARSET_INFO *default_client_charset_info; -MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, - my_bool default_value, uint server_capabilities); +MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc, + uint fields, my_bool default_value, + uint server_capabilities); void free_rows(MYSQL_DATA *cur); void free_old_query(MYSQL *mysql); void end_server(MYSQL *mysql); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 562da594fea..5d153317150 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, 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 @@ -1254,7 +1254,7 @@ MYSQL_FIELD *cli_list_fields(MYSQL *mysql) return NULL; mysql->field_count= (uint) query->rows; - return unpack_fields(query,&mysql->field_alloc, + return unpack_fields(mysql, query,&mysql->field_alloc, mysql->field_count, 1, mysql->server_capabilities); } @@ -1314,7 +1314,7 @@ mysql_list_processes(MYSQL *mysql) if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0, protocol_41(mysql) ? 7 : 5))) DBUG_RETURN(NULL); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0, mysql->server_capabilities))) DBUG_RETURN(0); mysql->status=MYSQL_STATUS_GET_RESULT; @@ -1891,7 +1891,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7))) DBUG_RETURN(1); - if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, + if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root, field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql-common/client.c b/sql-common/client.c index 0df7c242969..51911d913c7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2003, 2012, 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 @@ -1268,7 +1268,7 @@ static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, ***************************************************************************/ MYSQL_FIELD * -unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, +unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, my_bool default_value, uint server_capabilities) { MYSQL_ROWS *row; @@ -1281,6 +1281,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, if (!result) { free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(0); } bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields); @@ -1308,6 +1309,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, field->org_name_length= lengths[5]; /* Unpack fixed length parts */ + if (lengths[6] != 12) + { + /* malformed packet. signal an error. */ + free_rows(data); /* Free old data */ + set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate); + DBUG_RETURN(0); + } + pos= (uchar*) row->data[6]; field->charsetnr= uint2korr(pos); field->length= (uint) uint4korr(pos+2); @@ -2868,7 +2877,7 @@ get_info: if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) DBUG_RETURN(1); - if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, + if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc, (uint) field_count,0, mysql->server_capabilities))) DBUG_RETURN(1); diff --git a/sql/protocol.cc b/sql/protocol.cc index 5a727d94c46..a74f6084df4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, 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 @@ -620,6 +620,8 @@ bool Protocol::send_fields(List *list, uint flags) /* Store fixed length fields */ pos= (char*) local_packet->ptr()+local_packet->length(); *pos++= 12; // Length of packed fields + /* inject a NULL to test the client */ + DBUG_EXECUTE_IF("poison_rs_fields", pos[-1]= 0xfb;); if (item->collation.collation == &my_charset_bin || thd_charset == NULL) { /* No conversion */ From 521deaf36f3ae6686ebea64afe5d3195ad3f80d2 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 29 Jun 2012 18:24:43 +0400 Subject: [PATCH 46/55] minor update to make MSVS happy --- sql/field.cc | 2 +- sql/sql_yacc.yy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1c937755c0c..ff631edd8d4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10231,7 +10231,7 @@ Create_field::Create_field(Field *old_field,Field *orig_field) if (length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 854ba432362..7a6981f778a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5042,7 +5042,7 @@ type: if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), From 91c8e79fcd98bb586f32b22f5d67fcd5ae08ae28 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Tue, 3 Jul 2012 18:00:21 +0530 Subject: [PATCH 47/55] BUG#11762667:MYSQLBINLOG IGNORES ERRORS WHILE WRITING OUTPUT This is a followup patch for the bug enabling the test i_binlog.binlog_mysqlbinlog_file_write.test this was disabled in mysql trunk and mysql 5.5 as in the release build mysqlbinlog was not debug compiled whereas the mysqld was. Since have_debug.inc script checks only for mysqld to be debug compiled, the test was not being skipped on release builds. We resolve this problem by creating a new inc file mysqlbinlog_have_debug.inc which checks exclusively for mysqlbinlog to be debug compiled. if not it skips the test. mysql-test/include/mysqlbinlog_have_debug.inc: new inc file to check if mysqlbinlog is debug compiled. --- mysql-test/include/mysqlbinlog_have_debug.inc | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mysql-test/include/mysqlbinlog_have_debug.inc diff --git a/mysql-test/include/mysqlbinlog_have_debug.inc b/mysql-test/include/mysqlbinlog_have_debug.inc new file mode 100644 index 00000000000..14da1379ecd --- /dev/null +++ b/mysql-test/include/mysqlbinlog_have_debug.inc @@ -0,0 +1,34 @@ +############################################# +# checks if mysqlbinlog is debug compiled +# this "cannot" be done simply by using +# have_debug.inc +############################################# + +--disable_query_log +--let $temp_out_help_file=$MYSQL_TMP_DIR/mysqlbinlog_help.tmp +--exec $MYSQL_BINLOG --help>$temp_out_help_file +let log_tmp=$temp_out_help_file; +--let $temp_inc=$MYSQL_TMP_DIR/temp.inc +let inc_tmp=$temp_inc; + +--perl +use strict; +my $tmp_file= $ENV{'log_tmp'} or die "log_tmp not set"; +open(FILE, "$tmp_file") or die("Unable to open $tmp_file: $!\n"); +my $count = () = grep(/Output debug log/g,); +close FILE; + +my $temp_inc= $ENV{'inc_tmp'} or die "temp_inc not set"; +open(FILE_INC,">", "$temp_inc") or die("can't open file \"$temp_inc\": $!"); +print FILE_INC '--let $is_debug= '.$count; +close FILE_INC; +EOF +--source $temp_inc + +if (!$is_debug) +{ + --skip mysqlbinlog needs to be debug compiled +} +--remove_file $temp_out_help_file +--remove_file $temp_inc +--enable_query_log From 048577429f3adcb27100ace3dd6fd4579bcd9e53 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 5 Jul 2012 13:41:16 +0300 Subject: [PATCH 48/55] Bug #13889741: HANDLE_FATAL_SIGNAL IN _DB_ENTER_ | HANDLE_FATAL_SIGNAL IN STRNLEN Fixed the following bounds checking problems : 1. in check_if_legal_filename() make sure the null terminated string is long enough before accessing the bytes in it. Prevents pottential read-past-buffer-end 2. in my_wc_mb_filename() of the filename charset check for the end of the destination buffer before sending single byte characters into it. Prevents write-past-end-of-buffer (and garbaling stack in the cases reported here) errors. Added test cases. --- mysys/my_access.c | 3 ++- strings/ctype-utf8.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysys/my_access.c b/mysys/my_access.c index 210946d50a8..43917da7f98 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -148,7 +148,8 @@ static char reserved_map[256]= int check_if_legal_tablename(const char *name) { DBUG_ENTER("check_if_legal_tablename"); - DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) && + DBUG_RETURN(name[0] != 0 && name[1] != 0 && + (reserved_map[(uchar) name[0]] & 1) && (reserved_map[(uchar) name[1]] & 2) && (reserved_map[(uchar) name[2]] & 4) && str_list_find(&reserved_names[1], name)); diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 205f8c61ddd..a0e69feedab 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -4326,6 +4326,10 @@ my_wc_mb_filename(CHARSET_INFO *cs __attribute__((unused)), { int code; char hex[]= "0123456789abcdef"; + + if (s >= e) + return MY_CS_TOOSMALL; + if (wc < 128 && filename_safe_char[wc]) { *s= (uchar) wc; From e3c8fb4a1cf2984cf1aa1fe31ba828de550f619c Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 5 Jul 2012 14:37:48 +0300 Subject: [PATCH 49/55] Bug#14275000 Fixes for BUG11761686 left a flaw that managed to slip away from testing. Only effective filtering branch was actually tested with a regression test added to rpl_filter_tables_not_exist. The reason of the failure is destuction of too early mem-root-allocated memory at the end of the deferred User-var's do_apply_event(). Fixed with bypassing free_root() in the deferred execution branch. Deallocation of created in do_apply_event() items is done by the base code through THD::cleanup_after_query() -> free_items() that the parent Query can't miss. sql/log_event.cc: Do not call free_root() in case the deferred User-var event. Necessary methods to the User-var class are added, do_apply_event() refined. sql/log_event.h: Necessary methods to avoid destoying mem-root-based memory at User-var applying are defined. --- sql/log_event.cc | 16 ++++++++++++---- sql/log_event.h | 11 ++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..1822951cccf 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5640,6 +5640,9 @@ User_var_log_event:: User_var_log_event(const char* buf, const Format_description_log_event* description_event) :Log_event(buf, description_event) +#ifndef MYSQL_CLIENT + , deferred(false) +#endif { /* The Post-Header is empty. The Variable Data part begins immediately. */ buf+= description_event->common_header_len + @@ -5848,7 +5851,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) CHARSET_INFO *charset; if (rli->deferred_events_collecting) + { + set_deferred(); return rli->deferred_events->add(this); + } if (!(charset= get_charset(charset_number, MYF(MY_WME)))) return 1; @@ -5900,7 +5906,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) return 0; } } - Item_func_set_user_var e(user_var_name, it); + + Item_func_set_user_var *e= new Item_func_set_user_var(user_var_name, it); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) @@ -5909,7 +5916,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) crash the server, so if fix fields fails, we just return with an error. */ - if (e.fix_fields(thd, 0)) + if (e->fix_fields(thd, 0)) return 1; /* @@ -5917,8 +5924,9 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) a single record and with a single column. Thus, like a column value, it could always have IMPLICIT derivation. */ - e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); - free_root(thd->mem_root,0); + e->update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0); + if (!is_deferred()) + free_root(thd->mem_root,0); return 0; } diff --git a/sql/log_event.h b/sql/log_event.h index 39cd55f313e..e755b6a5a41 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2483,11 +2483,13 @@ public: uint charset_number; bool is_null; #ifndef MYSQL_CLIENT + bool deferred; User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg) :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg), - val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg) + val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), + deferred(false) { is_null= !val; } void pack_info(Protocol* protocol); #else @@ -2500,6 +2502,13 @@ public: Log_event_type get_type_code() { return USER_VAR_EVENT;} #ifndef MYSQL_CLIENT bool write(IO_CACHE* file); + /* + Getter and setter for deferred User-event. + Returns true if the event is not applied directly + and which case the applier adjusts execution path. + */ + bool is_deferred() { return deferred; } + void set_deferred() { deferred= val; } #endif bool is_valid() const { return 1; } From a1425b103248672ecb966cfc0efb0ba17d6b1d19 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 15:10:07 +0200 Subject: [PATCH 50/55] Refactor mysql_client_test.c into a framework part and a test part --- tests/Makefile.am | 1 + tests/mysql_client_fw.c | 1375 +++++++++++++++++++++++++++++++++++++ tests/mysql_client_test.c | 1358 +----------------------------------- 3 files changed, 1381 insertions(+), 1353 deletions(-) create mode 100644 tests/mysql_client_fw.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 876db7e8475..4929fa7ba9b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -47,6 +47,7 @@ LDADD = @CLIENT_EXTRA_LDFLAGS@ \ mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) mysql_client_test_SOURCES= mysql_client_test.c\ $(top_srcdir)/mysys/my_memmem.c +mysql_client_test.o: mysql_client_fw.c insert_test_SOURCES= insert_test.c select_test_SOURCES= select_test.c diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c new file mode 100644 index 00000000000..27a06501d7a --- /dev/null +++ b/tests/mysql_client_fw.c @@ -0,0 +1,1375 @@ +/* Copyright (c) 2012, 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 */ + +#include +#include +#include +#include +#include +#include +#include + +#define VER "2.1" +#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ +#define MAX_KEY MAX_INDEXES +#define MAX_SERVER_ARGS 64 + +/* set default options */ +static int opt_testcase = 0; +static char *opt_db= 0; +static char *opt_user= 0; +static char *opt_password= 0; +static char *opt_host= 0; +static char *opt_unix_socket= 0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name= 0; +#endif +static unsigned int opt_port; +static my_bool tty_password= 0, opt_silent= 0; + +static MYSQL *mysql= 0; +static char current_db[]= "client_test_db"; +static unsigned int test_count= 0; +static unsigned int opt_count= 0; +static unsigned int iter_count= 0; +static my_bool have_innodb= FALSE; + +static const char *opt_basedir= "./"; +static const char *opt_vardir= "mysql-test/var"; + +static longlong opt_getopt_ll_test= 0; + +static int embedded_server_arg_count= 0; +static char *embedded_server_args[MAX_SERVER_ARGS]; + +static const char *embedded_server_groups[]= { +"server", +"embedded", +"mysql_client_test_SERVER", +NullS +}; + +static time_t start_time, end_time; +static double total_time; + +const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; + +struct my_tests_st +{ +const char *name; +void (*function)(); +}; + +#define myheader(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (opt_silent < 2) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ + opt_count, str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +#define myheader_r(str) \ +DBUG_PRINT("test", ("name: %s", str)); \ + if (!opt_silent) \ + { \ + fprintf(stdout, "\n\n#####################################\n"); \ + fprintf(stdout, "%s", str); \ + fprintf(stdout, " \n#####################################\n"); \ + } + +static void print_error(const char *msg); +static void print_st_error(MYSQL_STMT *stmt, const char *msg); +static void client_disconnect(MYSQL* mysql, my_bool drop_db); + + +/* +Abort unless given experssion is non-zero. + +SYNOPSIS +DIE_UNLESS(expr) + +DESCRIPTION +We can't use any kind of system assert as we need to +preserve tested invariants in release builds as well. +*/ + +#define DIE_UNLESS(expr) \ +((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE_IF(expr) \ +((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) +#define DIE(expr) \ +die(__FILE__, __LINE__, #expr) + +static void die(const char *file, int line, const char *expr) +{ + fflush(stdout); + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + fflush(stderr); + exit(1); +} + + +#define myerror(msg) print_error(msg) +#define mysterror(stmt, msg) print_st_error(stmt, msg) + +#define myquery(RES) \ +{ \ + int r= (RES); \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define myquery_r(r) \ +{ \ + if (r) \ + myerror(NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r == 0); \ +} + +#define check_execute_r(stmt, r) \ +{ \ + if (r) \ + mysterror(stmt, NULL); \ + DIE_UNLESS(r != 0); \ +} + +#define check_stmt(stmt) \ +{ \ + if ( stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt != 0); \ +} + +#define check_stmt_r(stmt) \ +{ \ + if (stmt == 0) \ + myerror(NULL); \ + DIE_UNLESS(stmt == 0); \ +} + +#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} + + +/* A workaround for Sun Forte 5.6 on Solaris x86 */ + +static int cmp_double(double *a, double *b) +{ + return *a == *b; +} + + +/* Print the error message */ + +static void print_error(const char *msg) +{ + if (!opt_silent) + { + if (mysql && mysql_errno(mysql)) + { + if (mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + + +static void print_st_error(MYSQL_STMT *stmt, const char *msg) +{ + if (!opt_silent) + { + if (stmt && mysql_stmt_errno(stmt)) + { + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } +} + +/* +Enhanced version of mysql_client_init(), which may also set shared memory +base on Windows. +*/ +static MYSQL *mysql_client_init(MYSQL* con) +{ + MYSQL* res = mysql_init(con); + #ifdef HAVE_SMEM + if (res && shared_memory_base_name) + mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); + #endif + return res; +} + +/* +Disable direct calls of mysql_init, as it disregards shared memory base. +*/ +#define mysql_init(A) Please use mysql_client_init instead of mysql_init + + +/* Check if the connection has InnoDB tables */ + +static my_bool check_have_innodb(MYSQL *conn) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + my_bool result; + + rc= mysql_query(conn, "show variables like 'have_innodb'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= strcmp(row[1], "YES") == 0; + mysql_free_result(res); + return result; +} + + +/* +This is to be what mysql_query() is for mysql_real_query(), for +mysql_simple_prepare(): a variant without the 'length' parameter. +*/ + +static MYSQL_STMT *STDCALL +mysql_simple_prepare(MYSQL *mysql_arg, const char *query) +{ + MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); + if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) + { + mysql_stmt_close(stmt); + return 0; + } + return stmt; +} + + +/** +Connect to the server with options given by arguments to this application, +stored in global variables opt_host, opt_user, opt_password, opt_db, +opt_port and opt_unix_socket. + +@param flag[in] client_flag passed on to mysql_real_connect +@param protocol[in] MYSQL_PROTOCOL_* to use for this connection +@param auto_reconnect[in] set to 1 for auto reconnect + +@return pointer to initialized and connected MYSQL object +*/ +static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) +{ + MYSQL* mysql; + int rc; + static char query[MAX_TEST_QUERY_LENGTH]; + myheader_r("client_connect"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a connection to '%s' ...", + opt_host ? opt_host : ""); + + if (!(mysql= mysql_client_init(NULL))) + { + opt_silent= 0; + myerror("mysql_client_init() failed"); + exit(1); + } + /* enable local infile, in non-binary builds often disabled by default */ + mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); + + if (!(mysql_real_connect(mysql, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, flag))) + { + opt_silent= 0; + myerror("connection failed"); + mysql_close(mysql); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + mysql->reconnect= auto_reconnect; + + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(mysql, TRUE); + + if (!opt_silent) + { + fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", + mysql_get_server_info(mysql), + (ulong) mysql_get_server_version(mysql)); + fprintf(stdout, "\n Creating a test database '%s' ...", current_db); + } + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); + + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "USE ", current_db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + have_innodb= check_have_innodb(mysql); + + if (!opt_silent) + fprintf(stdout, "OK"); + + return mysql; +} + + +/* Close the connection */ + +static void client_disconnect(MYSQL* mysql, my_bool drop_db) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + + myheader_r("client_disconnect"); + + if (mysql) + { + if (drop_db) + { + if (!opt_silent) + fprintf(stdout, "\n dropping the test database '%s' ...", current_db); + strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); + + mysql_query(mysql, query); + if (!opt_silent) + fprintf(stdout, "OK"); + } + + if (!opt_silent) + fprintf(stdout, "\n closing the connection ..."); + mysql_close(mysql); + if (!opt_silent) + fprintf(stdout, "OK\n"); + } +} + + +/* Print dashes */ + +static void my_print_dashes(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + + mysql_field_seek(result, 0); + fputc('\t', stdout); + fputc('+', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + for(j= 0; j < field->max_length+2; j++) + fputc('-', stdout); + fputc('+', stdout); + } + fputc('\n', stdout); +} + + +/* Print resultset metadata information */ + +static void my_print_result_metadata(MYSQL_RES *result) +{ + MYSQL_FIELD *field; + unsigned int i, j; + unsigned int field_count; + + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\n', stdout); + fputc('\n', stdout); + } + + field_count= mysql_num_fields(result); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + j= strlen(field->name); + if (j < field->max_length) + j= field->max_length; + if (j < 4 && !IS_NOT_NULL(field->flags)) + j= 4; + field->max_length= j; + } + if (!opt_silent) + { + my_print_dashes(result); + fputc('\t', stdout); + fputc('|', stdout); + } + + mysql_field_seek(result, 0); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + fprintf(stdout, " %-*s |", (int) field->max_length, field->name); + } + if (!opt_silent) + { + fputc('\n', stdout); + my_print_dashes(result); + } +} + + +/* Process the result set */ + +static int my_process_result_set(MYSQL_RES *result) +{ + MYSQL_ROW row; + MYSQL_FIELD *field; + unsigned int i; + unsigned int row_count= 0; + + if (!result) + return 0; + + my_print_result_metadata(result); + + while ((row= mysql_fetch_row(result)) != NULL) + { + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (row[i] == NULL) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + + if (mysql_errno(mysql) != 0) + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + else + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + return row_count; +} + + +static int my_process_result(MYSQL *mysql_arg) +{ + MYSQL_RES *result; + int row_count; + + if (!(result= mysql_store_result(mysql_arg))) + return 0; + + row_count= my_process_result_set(result); + + mysql_free_result(result); + return row_count; +} + + +/* Process the statement result set */ + +#define MAX_RES_FIELDS 50 +#define MAX_FIELD_DATA_SIZE 255 + +static int my_process_stmt_result(MYSQL_STMT *stmt) +{ + int field_count; + int row_count= 0; + MYSQL_BIND buffer[MAX_RES_FIELDS]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; + ulong length[MAX_RES_FIELDS]; + my_bool is_null[MAX_RES_FIELDS]; + int rc, i; + + if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ + { + while (!mysql_stmt_fetch(stmt)) + row_count++; + return row_count; + } + + field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); + + bzero((char*) buffer, sizeof(buffer)); + bzero((char*) length, sizeof(length)); + bzero((char*) is_null, sizeof(is_null)); + + for(i= 0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; + buffer[i].length= &length[i]; + buffer[i].buffer= (void *) data[i]; + buffer[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_result(stmt, buffer); + check_execute(stmt, rc); + + rc= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + mysql_field_seek(result, 0); + for (i= 0; i < field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (is_null[i]) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + { + data[i][0]= '\0'; /* unmodified buffer */ + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + } + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + mysql_free_result(result); + return row_count; +} + + +/* Prepare statement, execute, and process result set for given query */ + +int my_stmt_result(const char *buff) +{ + MYSQL_STMT *stmt; + int row_count; + int rc; + + if (!opt_silent) + fprintf(stdout, "\n\n %s", buff); + stmt= mysql_simple_prepare(mysql, buff); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + + return row_count; +} + + +/* Utility function to verify a particular column data */ + +static void verify_col_data(const char *table, const char *col, +const char *exp_data) +{ + static char query[MAX_TEST_QUERY_LENGTH]; + MYSQL_RES *result; + MYSQL_ROW row; + int rc, field= 1; + + if (table && col) + { + strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); + if (!opt_silent) + fprintf(stdout, "\n %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result= mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + if (strcmp(row[field], exp_data)) + { + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + DIE_UNLESS(FALSE); + } + mysql_free_result(result); +} + + +/* Utility function to verify the field members */ + +#define verify_prepare_field(result,no,name,org_name,type,table, \ +org_table,db,length,def) \ +do_verify_prepare_field((result),(no),(name),(org_name),(type), \ +(table),(org_table),(db),(length),(def), \ +__FILE__, __LINE__) + +static void do_verify_prepare_field(MYSQL_RES *result, +unsigned int no, const char *name, +const char *org_name, +enum enum_field_types type, +const char *table, +const char *org_table, const char *db, +unsigned long length, const char *def, +const char *file, int line) +{ + MYSQL_FIELD *field; + CHARSET_INFO *cs; + ulonglong expected_field_length; + + if (!(field= mysql_fetch_field_direct(result, no))) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + cs= get_charset(field->charsetnr, 0); + DIE_UNLESS(cs); + if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) + expected_field_length= UINT_MAX32; + if (!opt_silent) + { + fprintf(stdout, "\n field[%d]:", no); + fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", + field->org_name, org_name); + fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); + if (table) + fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", + field->table, table); + if (org_table) + fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", + field->org_table, org_table); + fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", + field->length, expected_field_length); + fprintf(stdout, "\n maxlength:`%ld`", field->max_length); + fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", + field->def ? field->def : "(null)", def ? def: "(null)"); + fprintf(stdout, "\n"); + } + DIE_UNLESS(strcmp(field->name, name) == 0); + DIE_UNLESS(strcmp(field->org_name, org_name) == 0); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + { + if (field->type != type) + { + fprintf(stderr, + "Expected field type: %d, got type: %d in file %s, line %d\n", + (int) type, (int) field->type, file, line); + DIE_UNLESS(field->type == type); + } + } + if (table) + DIE_UNLESS(strcmp(field->table, table) == 0); + if (org_table) + DIE_UNLESS(strcmp(field->org_table, org_table) == 0); + DIE_UNLESS(strcmp(field->db, db) == 0); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + if (length && (field->length != expected_field_length)) + { + fprintf(stderr, "Expected field length: %llu, got length: %lu\n", + expected_field_length, field->length); + DIE_UNLESS(field->length == expected_field_length); + } + if (def) + DIE_UNLESS(strcmp(field->def, def) == 0); +} + + +/* Utility function to verify the parameter count */ + +static void verify_param_count(MYSQL_STMT *stmt, long exp_count) +{ + long param_count= mysql_stmt_param_count(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", + param_count, exp_count); + DIE_UNLESS(param_count == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) +{ + ulonglong affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total affected rows */ + +static void verify_affected_rows(ulonglong exp_count) +{ + ulonglong affected_rows= mysql_affected_rows(mysql); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); +} + + +/* Utility function to verify the total fields count */ + +static void verify_field_count(MYSQL_RES *result, uint exp_count) +{ + uint field_count= mysql_num_fields(result); + if (!opt_silent) + fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", + field_count, exp_count); + DIE_UNLESS(field_count == exp_count); +} + + +/* Utility function to execute a query using prepare-execute */ + +#ifndef EMBEDDED_LIBRARY +static void execute_prepare_query(const char *query, ulonglong exp_count) +{ + MYSQL_STMT *stmt; + ulonglong affected_rows; + int rc; + + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + rc= mysql_stmt_execute(stmt); + myquery(rc); + + affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + + DIE_UNLESS(affected_rows == exp_count); + mysql_stmt_close(stmt); +} +#endif + +/* +Accepts arbitrary number of queries and runs them against the database. +Used to fill tables for each test. +*/ + +void fill_tables(const char **query_list, unsigned query_count) +{ + int rc; + const char **query; + DBUG_ENTER("fill_tables"); + for (query= query_list; query < query_list + query_count; + ++query) + { + rc= mysql_query(mysql, *query); + myquery(rc); + } + DBUG_VOID_RETURN; +} + +/* +All state of fetch from one statement: statement handle, out buffers, +fetch position. +See fetch_n for for the only use case. +*/ + +enum { MAX_COLUMN_LENGTH= 255 }; + +typedef struct st_stmt_fetch +{ +const char *query; +unsigned stmt_no; +MYSQL_STMT *handle; +my_bool is_open; +MYSQL_BIND *bind_array; +char **out_data; +unsigned long *out_data_length; +unsigned column_count; +unsigned row_count; +} Stmt_fetch; + + +/* +Create statement handle, prepare it with statement, execute and allocate +fetch buffers. +*/ + +void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, +const char *query_arg) +{ + unsigned long type= CURSOR_TYPE_READ_ONLY; + int rc; + unsigned i; + MYSQL_RES *metadata; + DBUG_ENTER("stmt_fetch_init"); + + /* Save query and statement number for error messages */ + fetch->stmt_no= stmt_no_arg; + fetch->query= query_arg; + + fetch->handle= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); + check_execute(fetch->handle, rc); + + /* + The attribute is sent to server on execute and asks to open read-only + for result set + */ + mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, + (const void*) &type); + + rc= mysql_stmt_execute(fetch->handle); + check_execute(fetch->handle, rc); + + /* Find out total number of columns in result set */ + metadata= mysql_stmt_result_metadata(fetch->handle); + fetch->column_count= mysql_num_fields(metadata); + mysql_free_result(metadata); + + /* + Now allocate bind handles and buffers for output data: + calloc memory to reduce number of MYSQL_BIND members we need to + set up. + */ + + fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * + fetch->column_count); + fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); + fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * + fetch->column_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); + fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; + fetch->bind_array[i].buffer= fetch->out_data[i]; + fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; + fetch->bind_array[i].length= fetch->out_data_length + i; + } + + mysql_stmt_bind_result(fetch->handle, fetch->bind_array); + + fetch->row_count= 0; + fetch->is_open= TRUE; + + /* Ready for reading rows */ + DBUG_VOID_RETURN; +} + + +/* Fetch and print one row from cursor */ + +int stmt_fetch_fetch_row(Stmt_fetch *fetch) +{ + int rc; + unsigned i; + DBUG_ENTER("stmt_fetch_fetch_row"); + + if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) + { + ++fetch->row_count; + if (!opt_silent) + printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); + for (i= 0; i < fetch->column_count; ++i) + { + fetch->out_data[i][fetch->out_data_length[i]]= '\0'; + if (!opt_silent) + printf("column %d: %s\n", i+1, fetch->out_data[i]); + } + } + else + fetch->is_open= FALSE; + DBUG_RETURN(rc); +} + + +void stmt_fetch_close(Stmt_fetch *fetch) +{ + unsigned i; + DBUG_ENTER("stmt_fetch_close"); + + for (i= 0; i < fetch->column_count; ++i) + free(fetch->out_data[i]); + free(fetch->out_data); + free(fetch->out_data_length); + free(fetch->bind_array); + mysql_stmt_close(fetch->handle); + DBUG_VOID_RETURN; +} + +/* +For given array of queries, open query_count cursors and fetch +from them in simultaneous manner. +In case there was an error in one of the cursors, continue +reading from the rest. +*/ + +enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; + +my_bool fetch_n(const char **query_list, unsigned query_count, +enum fetch_type fetch_type) +{ + unsigned open_statements= query_count; + int rc, error_count= 0; + Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * + query_count); + Stmt_fetch *fetch; + DBUG_ENTER("fetch_n"); + + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + /* Init will exit(1) in case of error */ + stmt_fetch_init(fetch, fetch - fetch_array, + query_list[fetch - fetch_array]); + } + + if (fetch_type == USE_STORE_RESULT) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + rc= mysql_stmt_store_result(fetch->handle); + check_execute(fetch->handle, rc); + } + } + + while (open_statements) + { + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + { + if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) + { + open_statements--; + /* + We try to fetch from the rest of the statements in case of + error + */ + if (rc != MYSQL_NO_DATA) + { + fprintf(stderr, + "Got error reading rows from statement %d,\n" + "query is: %s,\n" + "error message: %s", (int) (fetch - fetch_array), + fetch->query, + mysql_stmt_error(fetch->handle)); + error_count++; + } + } + } + } + if (error_count) + fprintf(stderr, "Fetch FAILED"); + else + { + unsigned total_row_count= 0; + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + total_row_count+= fetch->row_count; + if (!opt_silent) + printf("Success, total rows fetched: %d\n", total_row_count); + } + for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) + stmt_fetch_close(fetch); + free(fetch_array); + DBUG_RETURN(error_count != 0); +} + +/* Separate thread query to test some cases */ + +static my_bool thread_query(const char *query) +{ + MYSQL *l_mysql; + my_bool error; + + error= 0; + if (!opt_silent) + fprintf(stdout, "\n in thread_query(%s)", query); + if (!(l_mysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + return 1; + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + error= 1; + goto end; + } + l_mysql->reconnect= 1; + if (mysql_query(l_mysql, query)) + { + fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); + error= 1; + goto end; + } + mysql_commit(l_mysql); + end: + mysql_close(l_mysql); + return error; +} + + +/* +Read and parse arguments and MySQL options from my.cnf +*/ + +static const char *client_test_load_default_groups[]= { "client", 0 }; +static char **defaults_argv; + +static struct my_option client_test_long_options[] = +{ +{"basedir", 'b', "Basedir for tests.", &opt_basedir, + &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"count", 't', "Number of times test to be executed", &opt_count, + &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, +{"database", 'D', "Database to use", &opt_db, &opt_db, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"debug", '#', "Output debug log", &default_dbug_option, + &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, +{"host", 'h', "Connect to host", &opt_host, &opt_host, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +{"port", 'P', "Port number to use for connection or 0 for default to, in " + "order of preference, my.cnf, $MYSQL_TCP_PORT, " + #if MYSQL_PORT_DEFAULT == 0 + "/etc/services, " + #endif + "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", + &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"server-arg", 'A', "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, +{"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + 0}, +#ifdef HAVE_SMEM +{"shared-memory-base-name", 'm', "Base name of shared memory.", + &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"socket", 'S', "Socket file to use for connection", + &opt_unix_socket, &opt_unix_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"testcase", 'c', + "May disable some code when runs as mysql-test-run testcase.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifndef DONT_ALLOW_USER_CHANGE +{"user", 'u', "User for login if not current user", &opt_user, + &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif +{"vardir", 'v', "Data dir for tests.", &opt_vardir, + &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +{"getopt-ll-test", 'g', "Option for testing bug in getopt library", + &opt_getopt_ll_test, &opt_getopt_ll_test, 0, + GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, +{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +static void usage(void) +{ +/* show the usage string when the user asks for this */ + putc('\n', stdout); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("By Monty, Venu, Kent and others\n"); + printf("\ +Copyright (C) 2002-2004 MySQL AB\n\ +This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); + printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); + my_print_help(client_test_long_options); + print_defaults("my", client_test_load_default_groups); + my_print_variables(client_test_long_options); +} + + +struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ + +static struct my_tests_st *my_testlist= 0; + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), +char *argument) +{ + switch (optid) { + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; + case 'c': + opt_testcase = 1; + break; + case 'p': + if (argument) + { + char *start=argument; + my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; + } + else + tty_password= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'A': + /* + When the embedded server is being tested, the test suite needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. The test suite + (mysql-test-run) never uses config files, just command-line options. + */ + if (!embedded_server_arg_count) + { + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + DIE("Can't use server argument"); + } + break; + case 'T': + { + struct my_tests_st *fptr; + + printf("All possible test names:\n\n"); + for (fptr= my_testlist; fptr->name; fptr++) + printf("%s\n", fptr->name); + exit(0); + break; + } + case '?': + case 'I': /* Info */ + usage(); + exit(0); + break; + } + return 0; +} + +static void get_options(int *argc, char ***argv) +{ + int ho_error; + + if ((ho_error= handle_options(argc, argv, client_test_long_options, + get_one_option))) + exit(ho_error); + + if (tty_password) + opt_password= get_tty_password(NullS); + return; +} + +/* +Print the test output on successful execution before exiting +*/ + +static void print_test_output() +{ + if (opt_silent < 3) + { + fprintf(stdout, "\n\n"); + fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout, "\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); + } +} + +/*************************************************************************** +main routine +***************************************************************************/ + + +int main(int argc, char **argv) +{ + struct my_tests_st *fptr; + my_testlist= get_my_tests(); + + MY_INIT(argv[0]); + + load_defaults("my", client_test_load_default_groups, &argc, &argv); + defaults_argv= argv; + get_options(&argc, &argv); + + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MySQL server"); + + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); + + total_time= 0; + for (iter_count= 1; iter_count <= opt_count; iter_count++) + { + /* Start of tests */ + test_count= 1; + start_time= time((time_t *)0); + if (!argc) + { + for (fptr= my_testlist; fptr->name; fptr++) + (*fptr->function)(); + } + else + { + for ( ; *argv ; argv++) + { + for (fptr= my_testlist; fptr->name; fptr++) + { + if (!strcmp(fptr->name, *argv)) + { + (*fptr->function)(); + break; + } + } + if (!fptr->name) + { + fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); + fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", + my_progname); + client_disconnect(mysql, 1); + free_defaults(defaults_argv); + exit(1); + } + } + } + + end_time= time((time_t *)0); + total_time+= difftime(end_time, start_time); + + /* End of tests */ + } + + client_disconnect(mysql, 1); /* disconnect from server */ + + free_defaults(defaults_argv); + print_test_output(); + + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + + mysql_server_end(); + + my_end(0); + + exit(0); +} diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index f553eb530ae..c38695db1b1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2012, 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 @@ -25,378 +25,12 @@ DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. */ - -#include -#include -#include -#include -#include -#include -#include - -#define VER "2.1" -#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ -#define MAX_KEY MAX_INDEXES -#define MAX_SERVER_ARGS 64 - -/* set default options */ -static int opt_testcase = 0; -static char *opt_db= 0; -static char *opt_user= 0; -static char *opt_password= 0; -static char *opt_host= 0; -static char *opt_unix_socket= 0; -#ifdef HAVE_SMEM -static char *shared_memory_base_name= 0; -#endif -static unsigned int opt_port; -static my_bool tty_password= 0, opt_silent= 0; - -static MYSQL *mysql= 0; -static char current_db[]= "client_test_db"; -static unsigned int test_count= 0; -static unsigned int opt_count= 0; -static unsigned int iter_count= 0; -static my_bool have_innodb= FALSE; - -static const char *opt_basedir= "./"; -static const char *opt_vardir= "mysql-test/var"; - -static longlong opt_getopt_ll_test= 0; - -static int embedded_server_arg_count= 0; -static char *embedded_server_args[MAX_SERVER_ARGS]; - -static const char *embedded_server_groups[]= { - "server", - "embedded", - "mysql_client_test_SERVER", - NullS -}; - -static time_t start_time, end_time; -static double total_time; - -const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; - -struct my_tests_st -{ - const char *name; - void (*function)(); -}; - -#define myheader(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (opt_silent < 2) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \ - opt_count, str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -#define myheader_r(str) \ -DBUG_PRINT("test", ("name: %s", str)); \ -if (!opt_silent) \ -{ \ - fprintf(stdout, "\n\n#####################################\n"); \ - fprintf(stdout, "%s", str); \ - fprintf(stdout, " \n#####################################\n"); \ -} - -static void print_error(const char *msg); -static void print_st_error(MYSQL_STMT *stmt, const char *msg); -static void client_disconnect(MYSQL* mysql, my_bool drop_db); - - /* - Abort unless given experssion is non-zero. - - SYNOPSIS - DIE_UNLESS(expr) - - DESCRIPTION - We can't use any kind of system assert as we need to - preserve tested invariants in release builds as well. + The fw.c file includes all the mysql_client_test framework; this file + contains only the actual tests, plus the list of test functions to call. */ -#define DIE_UNLESS(expr) \ - ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) -#define DIE_IF(expr) \ - ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) -#define DIE(expr) \ - die(__FILE__, __LINE__, #expr) - -static void die(const char *file, int line, const char *expr) -{ - fflush(stdout); - fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); - fflush(stderr); - exit(1); -} - - -#define myerror(msg) print_error(msg) -#define mysterror(stmt, msg) print_st_error(stmt, msg) - -#define myquery(RES) \ -{ \ - int r= (RES); \ - if (r) \ - myerror(NULL); \ - DIE_UNLESS(r == 0); \ -} - -#define myquery_r(r) \ -{ \ -if (r) \ - myerror(NULL); \ -DIE_UNLESS(r != 0); \ -} - -#define check_execute(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r == 0);\ -} - -#define check_execute_r(stmt, r) \ -{ \ -if (r) \ - mysterror(stmt, NULL); \ -DIE_UNLESS(r != 0);\ -} - -#define check_stmt(stmt) \ -{ \ -if ( stmt == 0) \ - myerror(NULL); \ -DIE_UNLESS(stmt != 0); \ -} - -#define check_stmt_r(stmt) \ -{ \ -if (stmt == 0) \ - myerror(NULL);\ -DIE_UNLESS(stmt == 0);\ -} - -#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} -#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} - - -/* A workaround for Sun Forte 5.6 on Solaris x86 */ - -static int cmp_double(double *a, double *b) -{ - return *a == *b; -} - - -/* Print the error message */ - -static void print_error(const char *msg) -{ - if (!opt_silent) - { - if (mysql && mysql_errno(mysql)) - { - if (mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - - -static void print_st_error(MYSQL_STMT *stmt, const char *msg) -{ - if (!opt_silent) - { - if (stmt && mysql_stmt_errno(stmt)) - { - if (stmt->mysql && stmt->mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - - fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } -} - -/* - Enhanced version of mysql_client_init(), which may also set shared memory - base on Windows. -*/ -static MYSQL *mysql_client_init(MYSQL* con) -{ - MYSQL* res = mysql_init(con); -#ifdef HAVE_SMEM - if (res && shared_memory_base_name) - mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); -#endif - return res; -} - -/* - Disable direct calls of mysql_init, as it disregards shared memory base. -*/ -#define mysql_init(A) Please use mysql_client_init instead of mysql_init - - -/* Check if the connection has InnoDB tables */ - -static my_bool check_have_innodb(MYSQL *conn) -{ - MYSQL_RES *res; - MYSQL_ROW row; - int rc; - my_bool result; - - rc= mysql_query(conn, "show variables like 'have_innodb'"); - myquery(rc); - res= mysql_use_result(conn); - DIE_UNLESS(res); - - row= mysql_fetch_row(res); - DIE_UNLESS(row); - - result= strcmp(row[1], "YES") == 0; - mysql_free_result(res); - return result; -} - - -/* - This is to be what mysql_query() is for mysql_real_query(), for - mysql_simple_prepare(): a variant without the 'length' parameter. -*/ - -static MYSQL_STMT *STDCALL -mysql_simple_prepare(MYSQL *mysql_arg, const char *query) -{ - MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); - if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) - { - mysql_stmt_close(stmt); - return 0; - } - return stmt; -} - - -/** - Connect to the server with options given by arguments to this application, - stored in global variables opt_host, opt_user, opt_password, opt_db, - opt_port and opt_unix_socket. - - @param flag[in] client_flag passed on to mysql_real_connect - @param protocol[in] MYSQL_PROTOCOL_* to use for this connection - @param auto_reconnect[in] set to 1 for auto reconnect - - @return pointer to initialized and connected MYSQL object -*/ -static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) -{ - MYSQL* mysql; - int rc; - static char query[MAX_TEST_QUERY_LENGTH]; - myheader_r("client_connect"); - - if (!opt_silent) - fprintf(stdout, "\n Establishing a connection to '%s' ...", - opt_host ? opt_host : ""); - - if (!(mysql= mysql_client_init(NULL))) - { - opt_silent= 0; - myerror("mysql_client_init() failed"); - exit(1); - } - /* enable local infile, in non-binary builds often disabled by default */ - mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); - - if (!(mysql_real_connect(mysql, opt_host, opt_user, - opt_password, opt_db ? opt_db:"test", opt_port, - opt_unix_socket, flag))) - { - opt_silent= 0; - myerror("connection failed"); - mysql_close(mysql); - fprintf(stdout, "\n Check the connection options using --help or -?\n"); - exit(1); - } - mysql->reconnect= auto_reconnect; - - if (!opt_silent) - fprintf(stdout, "OK"); - - /* set AUTOCOMMIT to ON*/ - mysql_autocommit(mysql, TRUE); - - if (!opt_silent) - { - fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", - mysql_get_server_info(mysql), - (ulong) mysql_get_server_version(mysql)); - fprintf(stdout, "\n Creating a test database '%s' ...", current_db); - } - strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); - - rc= mysql_query(mysql, query); - myquery(rc); - - strxmov(query, "USE ", current_db, NullS); - rc= mysql_query(mysql, query); - myquery(rc); - have_innodb= check_have_innodb(mysql); - - if (!opt_silent) - fprintf(stdout, "OK"); - - return mysql; -} - - -/* Close the connection */ - -static void client_disconnect(MYSQL* mysql, my_bool drop_db) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - - myheader_r("client_disconnect"); - - if (mysql) - { - if (drop_db) - { - if (!opt_silent) - fprintf(stdout, "\n dropping the test database '%s' ...", current_db); - strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS); - - mysql_query(mysql, query); - if (!opt_silent) - fprintf(stdout, "OK"); - } - - if (!opt_silent) - fprintf(stdout, "\n closing the connection ..."); - mysql_close(mysql); - if (!opt_silent) - fprintf(stdout, "OK\n"); - } -} - +#include "mysql_client_fw.c" /* Query processing */ @@ -443,471 +77,6 @@ static void client_query() } -/* Print dashes */ - -static void my_print_dashes(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - - mysql_field_seek(result, 0); - fputc('\t', stdout); - fputc('+', stdout); - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - for(j= 0; j < field->max_length+2; j++) - fputc('-', stdout); - fputc('+', stdout); - } - fputc('\n', stdout); -} - - -/* Print resultset metadata information */ - -static void my_print_result_metadata(MYSQL_RES *result) -{ - MYSQL_FIELD *field; - unsigned int i, j; - unsigned int field_count; - - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\n', stdout); - fputc('\n', stdout); - } - - field_count= mysql_num_fields(result); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - j= strlen(field->name); - if (j < field->max_length) - j= field->max_length; - if (j < 4 && !IS_NOT_NULL(field->flags)) - j= 4; - field->max_length= j; - } - if (!opt_silent) - { - my_print_dashes(result); - fputc('\t', stdout); - fputc('|', stdout); - } - - mysql_field_seek(result, 0); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - fprintf(stdout, " %-*s |", (int) field->max_length, field->name); - } - if (!opt_silent) - { - fputc('\n', stdout); - my_print_dashes(result); - } -} - - -/* Process the result set */ - -static int my_process_result_set(MYSQL_RES *result) -{ - MYSQL_ROW row; - MYSQL_FIELD *field; - unsigned int i; - unsigned int row_count= 0; - - if (!result) - return 0; - - my_print_result_metadata(result); - - while ((row= mysql_fetch_row(result)) != NULL) - { - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (row[i] == NULL) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, row[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - - if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); - else - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - return row_count; -} - - -static int my_process_result(MYSQL *mysql_arg) -{ - MYSQL_RES *result; - int row_count; - - if (!(result= mysql_store_result(mysql_arg))) - return 0; - - row_count= my_process_result_set(result); - - mysql_free_result(result); - return row_count; -} - - -/* Process the statement result set */ - -#define MAX_RES_FIELDS 50 -#define MAX_FIELD_DATA_SIZE 255 - -static int my_process_stmt_result(MYSQL_STMT *stmt) -{ - int field_count; - int row_count= 0; - MYSQL_BIND buffer[MAX_RES_FIELDS]; - MYSQL_FIELD *field; - MYSQL_RES *result; - char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; - ulong length[MAX_RES_FIELDS]; - my_bool is_null[MAX_RES_FIELDS]; - int rc, i; - - if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ - { - while (!mysql_stmt_fetch(stmt)) - row_count++; - return row_count; - } - - field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); - - bzero((char*) buffer, sizeof(buffer)); - bzero((char*) length, sizeof(length)); - bzero((char*) is_null, sizeof(is_null)); - - for(i= 0; i < field_count; i++) - { - buffer[i].buffer_type= MYSQL_TYPE_STRING; - buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; - buffer[i].length= &length[i]; - buffer[i].buffer= (void *) data[i]; - buffer[i].is_null= &is_null[i]; - } - - rc= mysql_stmt_bind_result(stmt, buffer); - check_execute(stmt, rc); - - rc= 1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); - rc= mysql_stmt_store_result(stmt); - check_execute(stmt, rc); - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - while ((rc= mysql_stmt_fetch(stmt)) == 0) - { - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - mysql_field_seek(result, 0); - for (i= 0; i < field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (is_null[i]) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (length[i] == 0) - { - data[i][0]= '\0'; /* unmodified buffer */ - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - } - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - DIE_UNLESS(rc == MYSQL_NO_DATA); - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - mysql_free_result(result); - return row_count; -} - - -/* Prepare statement, execute, and process result set for given query */ - -int my_stmt_result(const char *buff) -{ - MYSQL_STMT *stmt; - int row_count; - int rc; - - if (!opt_silent) - fprintf(stdout, "\n\n %s", buff); - stmt= mysql_simple_prepare(mysql, buff); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - check_execute(stmt, rc); - - row_count= my_process_stmt_result(stmt); - mysql_stmt_close(stmt); - - return row_count; -} - - -/* Utility function to verify a particular column data */ - -static void verify_col_data(const char *table, const char *col, - const char *exp_data) -{ - static char query[MAX_TEST_QUERY_LENGTH]; - MYSQL_RES *result; - MYSQL_ROW row; - int rc, field= 1; - - if (table && col) - { - strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); - if (!opt_silent) - fprintf(stdout, "\n %s", query); - rc= mysql_query(mysql, query); - myquery(rc); - - field= 0; - } - - result= mysql_use_result(mysql); - mytest(result); - - if (!(row= mysql_fetch_row(result)) || !row[field]) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - if (strcmp(row[field], exp_data)) - { - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", - row[field], exp_data); - DIE_UNLESS(FALSE); - } - mysql_free_result(result); -} - - -/* Utility function to verify the field members */ - -#define verify_prepare_field(result,no,name,org_name,type,table,\ - org_table,db,length,def) \ - do_verify_prepare_field((result),(no),(name),(org_name),(type), \ - (table),(org_table),(db),(length),(def), \ - __FILE__, __LINE__) - -static void do_verify_prepare_field(MYSQL_RES *result, - unsigned int no, const char *name, - const char *org_name, - enum enum_field_types type, - const char *table, - const char *org_table, const char *db, - unsigned long length, const char *def, - const char *file, int line) -{ - MYSQL_FIELD *field; - CHARSET_INFO *cs; - ulonglong expected_field_length; - - if (!(field= mysql_fetch_field_direct(result, no))) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - cs= get_charset(field->charsetnr, 0); - DIE_UNLESS(cs); - if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) - expected_field_length= UINT_MAX32; - if (!opt_silent) - { - fprintf(stdout, "\n field[%d]:", no); - fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); - fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", - field->org_name, org_name); - fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); - if (table) - fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", - field->table, table); - if (org_table) - fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", - field->org_table, org_table); - fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", - field->length, expected_field_length); - fprintf(stdout, "\n maxlength:`%ld`", field->max_length); - fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); - fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", - field->def ? field->def : "(null)", def ? def: "(null)"); - fprintf(stdout, "\n"); - } - DIE_UNLESS(strcmp(field->name, name) == 0); - DIE_UNLESS(strcmp(field->org_name, org_name) == 0); - /* - XXX: silent column specification change works based on number of - bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even - for CHAR(2) column if its character set is multibyte. - VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would - expect. - */ - if (cs->mbmaxlen == 1) - { - if (field->type != type) - { - fprintf(stderr, - "Expected field type: %d, got type: %d in file %s, line %d\n", - (int) type, (int) field->type, file, line); - DIE_UNLESS(field->type == type); - } - } - if (table) - DIE_UNLESS(strcmp(field->table, table) == 0); - if (org_table) - DIE_UNLESS(strcmp(field->org_table, org_table) == 0); - DIE_UNLESS(strcmp(field->db, db) == 0); - /* - Character set should be taken into account for multibyte encodings, such - as utf8. Field length is calculated as number of characters * maximum - number of bytes a character can occupy. - */ - if (length && (field->length != expected_field_length)) - { - fprintf(stderr, "Expected field length: %llu, got length: %lu\n", - expected_field_length, field->length); - DIE_UNLESS(field->length == expected_field_length); - } - if (def) - DIE_UNLESS(strcmp(field->def, def) == 0); -} - - -/* Utility function to verify the parameter count */ - -static void verify_param_count(MYSQL_STMT *stmt, long exp_count) -{ - long param_count= mysql_stmt_param_count(stmt); - if (!opt_silent) - fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", - param_count, exp_count); - DIE_UNLESS(param_count == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) -{ - ulonglong affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total affected rows */ - -static void verify_affected_rows(ulonglong exp_count) -{ - ulonglong affected_rows= mysql_affected_rows(mysql); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); -} - - -/* Utility function to verify the total fields count */ - -static void verify_field_count(MYSQL_RES *result, uint exp_count) -{ - uint field_count= mysql_num_fields(result); - if (!opt_silent) - fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", - field_count, exp_count); - DIE_UNLESS(field_count == exp_count); -} - - -/* Utility function to execute a query using prepare-execute */ - -#ifndef EMBEDDED_LIBRARY -static void execute_prepare_query(const char *query, ulonglong exp_count) -{ - MYSQL_STMT *stmt; - ulonglong affected_rows; - int rc; - - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - rc= mysql_stmt_execute(stmt); - myquery(rc); - - affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - - DIE_UNLESS(affected_rows == exp_count); - mysql_stmt_close(stmt); -} -#endif - /* Store result processing */ static void client_store_result() @@ -949,267 +118,6 @@ static void client_use_result() } -/* - Accepts arbitrary number of queries and runs them against the database. - Used to fill tables for each test. -*/ - -void fill_tables(const char **query_list, unsigned query_count) -{ - int rc; - const char **query; - DBUG_ENTER("fill_tables"); - for (query= query_list; query < query_list + query_count; - ++query) - { - rc= mysql_query(mysql, *query); - myquery(rc); - } - DBUG_VOID_RETURN; -} - -/* - All state of fetch from one statement: statement handle, out buffers, - fetch position. - See fetch_n for for the only use case. -*/ - -enum { MAX_COLUMN_LENGTH= 255 }; - -typedef struct st_stmt_fetch -{ - const char *query; - unsigned stmt_no; - MYSQL_STMT *handle; - my_bool is_open; - MYSQL_BIND *bind_array; - char **out_data; - unsigned long *out_data_length; - unsigned column_count; - unsigned row_count; -} Stmt_fetch; - - -/* - Create statement handle, prepare it with statement, execute and allocate - fetch buffers. -*/ - -void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg, - const char *query_arg) -{ - unsigned long type= CURSOR_TYPE_READ_ONLY; - int rc; - unsigned i; - MYSQL_RES *metadata; - DBUG_ENTER("stmt_fetch_init"); - - /* Save query and statement number for error messages */ - fetch->stmt_no= stmt_no_arg; - fetch->query= query_arg; - - fetch->handle= mysql_stmt_init(mysql); - - rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query)); - check_execute(fetch->handle, rc); - - /* - The attribute is sent to server on execute and asks to open read-only - for result set - */ - mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, - (const void*) &type); - - rc= mysql_stmt_execute(fetch->handle); - check_execute(fetch->handle, rc); - - /* Find out total number of columns in result set */ - metadata= mysql_stmt_result_metadata(fetch->handle); - fetch->column_count= mysql_num_fields(metadata); - mysql_free_result(metadata); - - /* - Now allocate bind handles and buffers for output data: - calloc memory to reduce number of MYSQL_BIND members we need to - set up. - */ - - fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * - fetch->column_count); - fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); - fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * - fetch->column_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); - fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; - fetch->bind_array[i].buffer= fetch->out_data[i]; - fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; - fetch->bind_array[i].length= fetch->out_data_length + i; - } - - mysql_stmt_bind_result(fetch->handle, fetch->bind_array); - - fetch->row_count= 0; - fetch->is_open= TRUE; - - /* Ready for reading rows */ - DBUG_VOID_RETURN; -} - - -/* Fetch and print one row from cursor */ - -int stmt_fetch_fetch_row(Stmt_fetch *fetch) -{ - int rc; - unsigned i; - DBUG_ENTER("stmt_fetch_fetch_row"); - - if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) - { - ++fetch->row_count; - if (!opt_silent) - printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count); - for (i= 0; i < fetch->column_count; ++i) - { - fetch->out_data[i][fetch->out_data_length[i]]= '\0'; - if (!opt_silent) - printf("column %d: %s\n", i+1, fetch->out_data[i]); - } - } - else - fetch->is_open= FALSE; - DBUG_RETURN(rc); -} - - -void stmt_fetch_close(Stmt_fetch *fetch) -{ - unsigned i; - DBUG_ENTER("stmt_fetch_close"); - - for (i= 0; i < fetch->column_count; ++i) - free(fetch->out_data[i]); - free(fetch->out_data); - free(fetch->out_data_length); - free(fetch->bind_array); - mysql_stmt_close(fetch->handle); - DBUG_VOID_RETURN; -} - -/* - For given array of queries, open query_count cursors and fetch - from them in simultaneous manner. - In case there was an error in one of the cursors, continue - reading from the rest. -*/ - -enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; - -my_bool fetch_n(const char **query_list, unsigned query_count, - enum fetch_type fetch_type) -{ - unsigned open_statements= query_count; - int rc, error_count= 0; - Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * - query_count); - Stmt_fetch *fetch; - DBUG_ENTER("fetch_n"); - - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - /* Init will exit(1) in case of error */ - stmt_fetch_init(fetch, fetch - fetch_array, - query_list[fetch - fetch_array]); - } - - if (fetch_type == USE_STORE_RESULT) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - rc= mysql_stmt_store_result(fetch->handle); - check_execute(fetch->handle, rc); - } - } - - while (open_statements) - { - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - { - if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) - { - open_statements--; - /* - We try to fetch from the rest of the statements in case of - error - */ - if (rc != MYSQL_NO_DATA) - { - fprintf(stderr, - "Got error reading rows from statement %d,\n" - "query is: %s,\n" - "error message: %s", (int) (fetch - fetch_array), - fetch->query, - mysql_stmt_error(fetch->handle)); - error_count++; - } - } - } - } - if (error_count) - fprintf(stderr, "Fetch FAILED"); - else - { - unsigned total_row_count= 0; - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - total_row_count+= fetch->row_count; - if (!opt_silent) - printf("Success, total rows fetched: %d\n", total_row_count); - } - for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) - stmt_fetch_close(fetch); - free(fetch_array); - DBUG_RETURN(error_count != 0); -} - -/* Separate thread query to test some cases */ - -static my_bool thread_query(const char *query) -{ - MYSQL *l_mysql; - my_bool error; - - error= 0; - if (!opt_silent) - fprintf(stdout, "\n in thread_query(%s)", query); - if (!(l_mysql= mysql_client_init(NULL))) - { - myerror("mysql_client_init() failed"); - return 1; - } - if (!(mysql_real_connect(l_mysql, opt_host, opt_user, - opt_password, current_db, opt_port, - opt_unix_socket, 0))) - { - myerror("connection failed"); - error= 1; - goto end; - } - l_mysql->reconnect= 1; - if (mysql_query(l_mysql, query)) - { - fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql)); - error= 1; - goto end; - } - mysql_commit(l_mysql); -end: - mysql_close(l_mysql); - return error; -} - - /* Query processing */ static void test_debug_example() @@ -18593,85 +17501,6 @@ static void test_bug13001491() } -/* - Read and parse arguments and MySQL options from my.cnf -*/ - -static const char *client_test_load_default_groups[]= { "client", 0 }; -static char **defaults_argv; - -static struct my_option client_test_long_options[] = -{ - {"basedir", 'b', "Basedir for tests.", &opt_basedir, - &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"count", 't', "Number of times test to be executed", &opt_count, - &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use", &opt_db, &opt_db, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", &opt_host, &opt_host, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"port", 'P', "Port number to use for connection or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " -#if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " -#endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"server-arg", 'A', "Send embedded server this as a parameter.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, - 0}, -#ifdef HAVE_SMEM - {"shared-memory-base-name", 'm', "Base name of shared memory.", - &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"socket", 'S', "Socket file to use for connection", - &opt_unix_socket, &opt_unix_socket, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"testcase", 'c', - "May disable some code when runs as mysql-test-run testcase.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifndef DONT_ALLOW_USER_CHANGE - {"user", 'u', "User for login if not current user", &opt_user, - &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif - {"vardir", 'v', "Data dir for tests.", &opt_vardir, - &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"getopt-ll-test", 'g', "Option for testing bug in getopt library", - &opt_getopt_ll_test, &opt_getopt_ll_test, 0, - GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - - -static void usage(void) -{ - /* show the usage string when the user asks for this */ - putc('\n', stdout); - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); - puts("By Monty, Venu, Kent and others\n"); - printf("\ -Copyright (C) 2002-2004 MySQL AB\n\ -This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ -and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); - my_print_help(client_test_long_options); - print_defaults("my", client_test_load_default_groups); - my_print_variables(client_test_long_options); -} - - static struct my_tests_st my_tests[]= { { "disable_query_logs", disable_query_logs }, { "test_view_sp_list_fields", test_view_sp_list_fields }, @@ -18926,181 +17755,4 @@ static struct my_tests_st my_tests[]= { }; -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch (optid) { - case '#': - DBUG_PUSH(argument ? argument : default_dbug_option); - break; - case 'c': - opt_testcase = 1; - break; - case 'p': - if (argument) - { - char *start=argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - opt_password= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - if (*start) - start[1]=0; - } - else - tty_password= 1; - break; - case 's': - if (argument == disabled_my_option) - opt_silent= 0; - else - opt_silent++; - break; - case 'A': - /* - When the embedded server is being tested, the test suite needs to be - able to pass command-line arguments to the embedded server so it can - locate the language files and data directory. The test suite - (mysql-test-run) never uses config files, just command-line options. - */ - if (!embedded_server_arg_count) - { - embedded_server_arg_count= 1; - embedded_server_args[0]= (char*) ""; - } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || - !(embedded_server_args[embedded_server_arg_count++]= - my_strdup(argument, MYF(MY_FAE)))) - { - DIE("Can't use server argument"); - } - break; - case 'T': - { - struct my_tests_st *fptr; - - printf("All possible test names:\n\n"); - for (fptr= my_tests; fptr->name; fptr++) - printf("%s\n", fptr->name); - exit(0); - break; - } - case '?': - case 'I': /* Info */ - usage(); - exit(0); - break; - } - return 0; -} - -static void get_options(int *argc, char ***argv) -{ - int ho_error; - - if ((ho_error= handle_options(argc, argv, client_test_long_options, - get_one_option))) - exit(ho_error); - - if (tty_password) - opt_password= get_tty_password(NullS); - return; -} - -/* - Print the test output on successful execution before exiting -*/ - -static void print_test_output() -{ - if (opt_silent < 3) - { - fprintf(stdout, "\n\n"); - fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", - test_count-1, opt_count); - fprintf(stdout, "\n Total execution time: %g SECS", total_time); - if (opt_count > 1) - fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); - - fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); - } -} - -/*************************************************************************** - main routine -***************************************************************************/ - - -int main(int argc, char **argv) -{ - struct my_tests_st *fptr; - - MY_INIT(argv[0]); - - load_defaults("my", client_test_load_default_groups, &argc, &argv); - defaults_argv= argv; - get_options(&argc, &argv); - - if (mysql_server_init(embedded_server_arg_count, - embedded_server_args, - (char**) embedded_server_groups)) - DIE("Can't initialize MySQL server"); - - /* connect to server with no flags, default protocol, auto reconnect true */ - mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); - - total_time= 0; - for (iter_count= 1; iter_count <= opt_count; iter_count++) - { - /* Start of tests */ - test_count= 1; - start_time= time((time_t *)0); - if (!argc) - { - for (fptr= my_tests; fptr->name; fptr++) - (*fptr->function)(); - } - else - { - for ( ; *argv ; argv++) - { - for (fptr= my_tests; fptr->name; fptr++) - { - if (!strcmp(fptr->name, *argv)) - { - (*fptr->function)(); - break; - } - } - if (!fptr->name) - { - fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); - fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", - my_progname); - client_disconnect(mysql, 1); - free_defaults(defaults_argv); - exit(1); - } - } - } - - end_time= time((time_t *)0); - total_time+= difftime(end_time, start_time); - - /* End of tests */ - } - - client_disconnect(mysql, 1); /* disconnect from server */ - - free_defaults(defaults_argv); - print_test_output(); - - while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); - - mysql_server_end(); - - my_end(0); - - exit(0); -} +static struct my_tests_st *get_my_tests() { return my_tests; } From aacb690bd52942d2152e661f451fb3b4dd8e0ccf Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 9 Jul 2012 16:36:50 +0200 Subject: [PATCH 51/55] Fixed compile error in mysql_client_test using gcc --- tests/mysql_client_fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c index 27a06501d7a..34a4c05215b 100644 --- a/tests/mysql_client_fw.c +++ b/tests/mysql_client_fw.c @@ -1190,7 +1190,7 @@ and you are welcome to modify and redistribute it under the GPL license\n"); } -struct my_tests_st *get_my_tests(); /* Will be defined in main .c file */ +static struct my_tests_st *get_my_tests(); /* To be defined in main .c file */ static struct my_tests_st *my_testlist= 0; From b21319483f708a9bdff43d2773b67043054f5a35 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 10:04:57 +0200 Subject: [PATCH 52/55] mysql_client_test did not build within limbysqld/examples --- libmysqld/examples/CMakeLists.txt | 3 ++- libmysqld/examples/Makefile.am | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libmysqld/examples/CMakeLists.txt b/libmysqld/examples/CMakeLists.txt index 2b900a1fa8f..d7f994d9b9f 100644 --- a/libmysqld/examples/CMakeLists.txt +++ b/libmysqld/examples/CMakeLists.txt @@ -17,7 +17,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/libmysqld/include ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/zlib + ${CMAKE_SOURCE_DIR}/tests ${CMAKE_SOURCE_DIR}/extra/yassl/include) # Currently does not work with DBUG, there are missing symbols reported. diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index a732b209e27..a0f1a64ffdc 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -35,7 +35,7 @@ link_sources: DEFS = -DEMBEDDED_LIBRARY INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \ -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ - $(openssl_includes) + -I$(top_srcdir)/tests $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ $(yassl_libs) LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @LIBDL@ $(CXXLDFLAGS) \ @NDB_SCI_LIBS@ @@ -51,6 +51,7 @@ mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) mysql_client_test_embedded_LINK = $(CXXLINK) nodist_mysql_client_test_embedded_SOURCES = mysql_client_test.c +mysql_client_test.o: $(top_srcdir)/tests/mysql_client_fw.c # Don't update the files from bitkeeper %::SCCS/s.% From 13f7f002886c18fc911f6cf6d5bd672f8c96d844 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Tue, 10 Jul 2012 14:23:17 +0530 Subject: [PATCH 53/55] BUG#11762670:MY_B_WRITE RETURN VALUE IGNORED Problem: ======= The return value from my_b_write is ignored by: `my_b_write_quoted', `my_b_write_bit',`Query_log_event::print_query_header' Most callers of `my_b_printf' ignore the return value. `log_event.cc' has many calls to it. Analysis: ======== `my_b_write' is used to write data into a file. If the write fails it sets appropriate error number and error message through my_error() function call and sets the IO_CACHE::error == -1. `my_b_printf' function is also used to write data into a file, it internally invokes my_b_write to do the write operation. Upon success it returns number of characters written to file and on error it returns -1 and sets the error through my_error() and also sets IO_CACHE::error == -1. Most of the event specific print functions for example `Create_file_log_event::print', `Execute_load_log_event::print' etc are the ones which make several calls to the above two functions and they do not check for the return value after the 'print' call. All the above mentioned abuse cases deal with the client side. Fix: === As part of bug fix a check for IO_CACHE::error == -1 has been added at a very high level after the call to the 'print' function. There are few more places where the return value of "my_b_write" is ignored those are mentioned below. +++ mysys/mf_iocache2.c 2012-06-04 07:03:15 +0000 @@ -430,7 +430,8 @@ memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); +++ sql/log.cc 2012-06-08 09:04:46 +0000 @@ -2388,7 +2388,12 @@ { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); At these places appropriate return value handlers have been added. client/mysqlbinlog.cc: check for IO_CACHE::error == -1 has been added after the call to the event specific print functions mysys/mf_iocache2.c: Added handler to check the written value of `my_b_write' sql/log.cc: Added handler to check the written value of `my_b_write' sql/log_event.cc: Added error simulation statements in `Create_file_log_event::print` and `Execute_load_query_log_event::print' sql/rpl_utility.h: Removed the extra ';' --- client/mysqlbinlog.cc | 13 ++++++++++++- mysys/mf_iocache2.c | 6 +++++- sql/log.cc | 5 ++++- sql/log_event.cc | 24 +++++++++++++++++++----- sql/rpl_utility.h | 2 +- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index e7840865a58..b5acfc5c169 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -784,8 +784,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, goto end; } else + { ce->print(result_file, print_event_info, TRUE); - + if (head->error == -1) + goto err; + } // If this binlog is not 3.23 ; why this test?? if (glob_description_event->binlog_version >= 3) { @@ -836,6 +839,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ce->print(result_file, print_event_info, TRUE); my_free((char*)ce->fname,MYF(MY_WME)); delete ce; + if (head->error == -1) + goto err; } else warning("Ignoring Execute_load_log_event as there is no " @@ -890,6 +895,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, { convert_path_to_forward_slashes(fname); exlq->print(result_file, print_event_info, fname); + if (head->error == -1) + { + if (fname) + my_free(fname, MYF(MY_WME)); + goto err; + } } else warning("Ignoring Execute_load_query since there is no " diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 828145b7931..dd56e332433 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -430,7 +430,11 @@ process_flags: memset(buffz, '0', minimum_width - length2); else memset(buffz, ' ', minimum_width - length2); - my_b_write(info, buffz, minimum_width - length2); + if (my_b_write(info, buffz, minimum_width - length2)) + { + my_afree(buffz); + goto err; + } my_afree(buffz); } diff --git a/sql/log.cc b/sql/log.cc index 3714f1190be..57c14b24782 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2388,7 +2388,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, { end= strxmov(buff, "# administrator command: ", NullS); buff_len= (ulong) (end - buff); - my_b_write(&log_file, (uchar*) buff, buff_len); + DBUG_EXECUTE_IF("simulate_slow_log_write_error", + {DBUG_SET("+d,simulate_file_write_error");}); + if(my_b_write(&log_file, (uchar*) buff, buff_len)) + tmp_errno= errno; } if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) || my_b_write(&log_file, (uchar*) ";\n",2) || diff --git a/sql/log_event.cc b/sql/log_event.cc index a47b3680d82..2ad740698c6 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6312,11 +6312,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info { Load_log_event::print(file, print_event_info, !check_fname_outside_temp_buf()); - /* - That one is for "file_id: etc" below: in mysqlbinlog we want the #, in - SHOW BINLOG EVENTS we don't. - */ - my_b_printf(&cache, "#"); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_create_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); + /* + That one is for "file_id: etc" below: in mysqlbinlog we want the #, in + SHOW BINLOG EVENTS we don't. + */ + my_b_printf(&cache, "#"); } my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len); @@ -6992,6 +6999,13 @@ void Execute_load_query_log_event::print(FILE* file, Write_on_release_cache cache(&print_event_info->head_cache, file); print_query_header(&cache, print_event_info); + /** + reduce the size of io cache so that the write function is called + for every call to my_b_printf(). + */ + DBUG_EXECUTE_IF ("simulate_execute_event_write_error", + {(&cache)->write_pos= (&cache)->write_end; + DBUG_SET("+d,simulate_file_write_error");}); if (local_fname) { diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* 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); From 86476179479eb14343e1d434a2345d9cad47a28a Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 10 Jul 2012 11:57:24 +0200 Subject: [PATCH 54/55] mysql_client_fw.c was not included in make dist --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4929fa7ba9b..3da18683f85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ myisam-big-rows.tst \ + mysql_client_fw.c \ CMakeLists.txt bin_PROGRAMS = mysql_client_test From dfa0093096f305a893fdd9baefe010523f94c4a5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Jul 2012 18:55:07 +0530 Subject: [PATCH 55/55]