From e104d49cb7428ea55bf6e640e2fe1720e900065a Mon Sep 17 00:00:00 2001 From: Karen Langford Date: Thu, 9 Jun 2011 17:41:20 +0200 Subject: [PATCH 01/10] Raise version number after cloning 5.1.58 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 901515fecb6..0948fe1349d 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.58], [], [mysql]) +AC_INIT([MySQL Server], [5.1.59], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 639605a91937681fa7256d0f5a2e216046d33d92 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Thu, 9 Jun 2011 23:30:52 +0700 Subject: [PATCH 02/10] Fixed bug#11840395 (formerly known as bug#60347: THE STRING "VERSIONDATA" SEEMS TO BE 'LEAKING' INTO THE SCHEMA NAME SPACE) and bug#12428824 (Parser stack overflow and crash in sp_add_used_routine with obscure query). The first problem was that attempts to call a stored function by its fully qualified name ended up with unwarranted error "ERROR 1305 (42000): FUNCTION someMixedCaseDb.my_function_name does not exist" if this function belonged to a schema that had uppercase letters in its name AND --lower_case_table_names was equal to either 1 or 2. The second problem was that 5.5 version of MySQL server might have crashed when a user tried to call stored function with too long name or too long database name (i.e if a function and database name combined occupied more than 2*3*64 bytes in utf8). This issue didn't affect versions of server < 5.5. The first problem was caused by the fact that in cases when a stored function was called by its fully qualified name we didn't lowercase name of its schema before performing look up of the function in mysql.proc table even although lower_case_table_names mode was on. As result we were unable to find this function since during its creation we store lowercased version of schema name in the system table in this mode and field for schema name uses binary collation. Calls to stored functions were unaffected by this problem since for them schema name is converted to lowercase as necessary. The reason for the second bug was that MySQL Server didn't check length of function name and database name before proceeding with execution of stored function. As a consequence too long database name or function name caused buffer overruns in places where the code assumes that their length is within fixed limits, like mdl_key_init() in 5.5. Again this issue didn't affect calls to stored procedures as for them length of schema name and procedure name are properly checked. This patch fixes both these bugs by adding calls to check_db_name() and check_routine_name() to grammar rule which corresponds to a call to a stored function. These functions ensure that length of database name and function name for routine called is within standard limit. Moreover call to check_db_name() handles conversion of database name to lowercase if --lower_case_table_names mode is on. Note that even although the second issue seems to be only reproducible in 5.5 we still add code fixing it to 5.1 to be on the safe side (and make code a bit more robust against possible future changes). --- mysql-test/r/sp-error.result | 16 ++++++++++++++++ mysql-test/r/sp.result | 15 +++++++++++++++ mysql-test/t/sp-error.test | 22 ++++++++++++++++++++++ mysql-test/t/sp.test | 18 ++++++++++++++++++ sql/sql_yacc.yy | 15 +++++++++++++++ 5 files changed, 86 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index ec2ba5747c3..2b7554b3eba 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1685,4 +1685,20 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; +# +# Bug#12428824 - PARSER STACK OVERFLOW AND CRASH IN SP_ADD_USED_ROUTINE +# WITH OBSCURE QUERY +# +SELECT very_long_fn_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999(); +ERROR 42000: Identifier name 'very_long_fn_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' is too long +CALL very_long_pr_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999(); +ERROR 42000: Identifier name 'very_long_pr_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' is too long +SELECT very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999.simple_func(); +ERROR 42000: Incorrect database name 'very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' +CALL very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999.simple_proc(); +ERROR 42000: Incorrect database name 'very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' +SELECT db_name.very_long_fn_name_111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999999999999999999(); +ERROR 42000: Identifier name 'very_long_fn_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' is too long +CALL db_name.very_long_pr_name_111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999999999999999999(); +ERROR 42000: Identifier name 'very_long_pr_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222' is too long End of 5.1 tests diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 2180a23b91a..c47263b77df 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -7053,6 +7053,21 @@ init_connect SET @@GLOBAL.init_connect= @old_init_connect; DROP PROCEDURE p2; DROP PROCEDURE p5; +# +# Bug#11840395 (formerly known as bug#60347): +# The string "versiondata" seems to be 'leaking' into the schema name space +# to be 'leaking' into the schema name space +# +DROP DATABASE IF EXISTS mixedCaseDbName; +CREATE DATABASE mixedCaseDbName; +CREATE PROCEDURE mixedCaseDbName.tryMyProc() begin end| +CREATE FUNCTION mixedCaseDbName.tryMyFunc() returns text begin return 'IT WORKS'; end +| +call mixedCaseDbName.tryMyProc(); +select mixedCaseDbName.tryMyFunc(); +mixedCaseDbName.tryMyFunc() +IT WORKS +DROP DATABASE mixedCaseDbName; # ------------------------------------------------------------------ # -- End of 5.1 tests # ------------------------------------------------------------------ diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 18a4a117939..7a04d89fdc2 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2471,4 +2471,26 @@ DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; +--echo # +--echo # Bug#12428824 - PARSER STACK OVERFLOW AND CRASH IN SP_ADD_USED_ROUTINE +--echo # WITH OBSCURE QUERY +--echo # + +--error ER_TOO_LONG_IDENT +SELECT very_long_fn_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999(); + +--error ER_TOO_LONG_IDENT +CALL very_long_pr_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999(); + +--error ER_WRONG_DB_NAME +SELECT very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999.simple_func(); + +--error ER_WRONG_DB_NAME +CALL very_long_db_name_1111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222225555555555555555555555555577777777777777777777777777777777777777777777777777777777777777777777777788888888999999999999999999999.simple_proc(); + +--error ER_TOO_LONG_IDENT +SELECT db_name.very_long_fn_name_111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999999999999999999(); + +--error ER_TOO_LONG_IDENT +CALL db_name.very_long_pr_name_111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999999999999999999(); --echo End of 5.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5cf050146dd..ddf035860e4 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8350,6 +8350,24 @@ SET @@GLOBAL.init_connect= @old_init_connect; DROP PROCEDURE p2; DROP PROCEDURE p5; +--echo # +--echo # Bug#11840395 (formerly known as bug#60347): +--echo # The string "versiondata" seems to be 'leaking' into the schema name space +--echo # to be 'leaking' into the schema name space +--echo # +--disable_warnings +DROP DATABASE IF EXISTS mixedCaseDbName; +--enable_warnings +CREATE DATABASE mixedCaseDbName; +DELIMITER |; +CREATE PROCEDURE mixedCaseDbName.tryMyProc() begin end| +CREATE FUNCTION mixedCaseDbName.tryMyFunc() returns text begin return 'IT WORKS'; end +| +DELIMITER ;| +call mixedCaseDbName.tryMyProc(); +select mixedCaseDbName.tryMyFunc(); +DROP DATABASE mixedCaseDbName; + --echo # ------------------------------------------------------------------ --echo # -- End of 5.1 tests --echo # ------------------------------------------------------------------ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4e24e69af42..719426015bd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8020,6 +8020,11 @@ function_call_generic: Create_func *builder; Item *item= NULL; + if (check_routine_name(&$1)) + { + MYSQL_YYABORT; + } + /* Implementation note: names are resolved with the following order: @@ -8083,6 +8088,16 @@ function_call_generic: version() (a vendor can specify any schema). */ + if (!$1.str || check_db_name(&$1)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), $1.str); + MYSQL_YYABORT; + } + if (check_routine_name(&$3)) + { + MYSQL_YYABORT; + } + builder= find_qualified_function_builder(thd); DBUG_ASSERT(builder); item= builder->create(thd, $1, $3, true, $5); From 7174bd385ca466e9c99808b93ee6eda0cd3964ea Mon Sep 17 00:00:00 2001 From: Sunanda Menon Date: Fri, 10 Jun 2011 07:38:09 +0200 Subject: [PATCH 03/10] Raise version number after cloning 5.0.94 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index fdfb7eae871..a06f726c738 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.94) +AM_INIT_AUTOMAKE(mysql, 5.0.95) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=94 +NDB_VERSION_BUILD=95 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 9827d4aa638c706041966efc49a3ac5a5726b4bf Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 11 Jul 2011 11:20:19 +0200 Subject: [PATCH 04/10] Bug#11765255 - 58201: VALGRIND/CRASH WHEN ORDERING BY MULTIPLE AGGREGATE FUNCTIONS We must allocate a larger ref_pointer_array. We failed to account for extra items allocated here: #0 find_order_in_list uint el= all_fields.elements; all_fields.push_front(order_item); /* Add new field to field list. */ ref_pointer_array[el]= order_item; order->item= ref_pointer_array + el; #1 setup_order #2 setup_without_group #3 JOIN::prepare --- mysql-test/r/order_by.result | 7 +++++ mysql-test/r/union.result | 57 ++++++++++++++++++++++++++++++++++++ mysql-test/t/order_by.test | 7 +++++ mysql-test/t/union.test | 41 ++++++++++++++++++++++++++ sql/sql_lex.cc | 3 ++ sql/sql_union.cc | 39 ++++++++++++++++++------ 6 files changed, 145 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 90b03711191..0c522aef290 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1664,4 +1664,11 @@ a 1 3 1 2 1 DROP TABLE t1; +# +# Bug#11765255 58201: +# VALGRIND/CRASH WHEN ORDERING BY MULTIPLE AGGREGATE FUNCTIONS +# +select 1 order by max(1) + min(1); +1 +1 End of 5.1 tests diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 1ee313a2b46..9966cb0f0d0 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1647,4 +1647,61 @@ b 1 2 DROP TABLE t1,t2; +# +# Bug#11765255 58201: +# VALGRIND/CRASH WHEN ORDERING BY MULTIPLE AGGREGATE FUNCTIONS +# +select 1 as foo +union +select 2 +union +select 3 +union +select 4 +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +; +foo +1 +prepare stmt1 from 'select 1 as foo +union +select 2 +union +select 3 +union +select 4 +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +'; +execute stmt1; +foo +1 +execute stmt1; +foo +1 +select 1 as foo +union +select 2 +union +select 3 +union +(select 4) +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +; +foo +1 +prepare stmt1 from 'select 1 as foo +union +select 2 +union +select 3 +union +(select 4) +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +'; +execute stmt1; +foo +1 +execute stmt1; +foo +1 +deallocate prepare stmt1; End of 5.1 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index e310d960c97..dec64ffc69d 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1508,4 +1508,11 @@ SELECT DISTINCT a,1 FROM t1 WHERE a <> 1 ORDER BY a DESC; DROP TABLE t1; +--echo # +--echo # Bug#11765255 58201: +--echo # VALGRIND/CRASH WHEN ORDERING BY MULTIPLE AGGREGATE FUNCTIONS +--echo # + +select 1 order by max(1) + min(1); + --echo End of 5.1 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index c8d5ea0f8e5..d61c02be45c 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1156,4 +1156,45 @@ SELECT * FROM t2 UNION SELECT * FROM t2 DROP TABLE t1,t2; +--echo # +--echo # Bug#11765255 58201: +--echo # VALGRIND/CRASH WHEN ORDERING BY MULTIPLE AGGREGATE FUNCTIONS +--echo # + +let $my_stmt= +select 1 as foo +union +select 2 +union +select 3 +union +select 4 +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +; + +eval $my_stmt; + +eval prepare stmt1 from '$my_stmt'; +execute stmt1; +execute stmt1; + +let $my_stmt= +select 1 as foo +union +select 2 +union +select 3 +union +(select 4) +order by max(42) + max(1) + max(1) + max(1) + max(1) + max(1) +; + +eval $my_stmt; + +eval prepare stmt1 from '$my_stmt'; +execute stmt1; +execute stmt1; + +deallocate prepare stmt1; + --echo End of 5.1 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f0289ab86ce..a7b23746155 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1987,6 +1987,9 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) if (ref_pointer_array) return 0; + // find_order_in_list() may need some extra space, so multiply by two. + order_group_num*= 2; + /* We have to create array in prepared statement memory if it is prepared statement diff --git a/sql/sql_union.cc b/sql/sql_union.cc index a70de945492..2be47d95a26 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1,5 +1,4 @@ -/* - Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -403,15 +402,27 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, fake_select_lex->table_list.empty(); DBUG_RETURN(TRUE); } + + /* + Fake st_select_lex should have item list for correct ref_array + allocation. + */ fake_select_lex->item_list= item_list; thd_arg->lex->current_select= fake_select_lex; + + /* + We need to add up n_sum_items in order to make the correct + allocation in setup_ref_array(). + */ + fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; + saved_error= fake_select_lex->join-> prepare(&fake_select_lex->ref_pointer_array, fake_select_lex->table_list.first, 0, 0, - fake_select_lex->order_list.elements, - fake_select_lex->order_list.first, + global_parameters->order_list.elements, // og_num + global_parameters->order_list.first, // order NULL, NULL, NULL, fake_select_lex, this); fake_select_lex->table_list.empty(); @@ -579,11 +590,21 @@ bool st_select_lex_unit::exec() } fake_select_lex->join->no_const_tables= TRUE; - /* - Fake st_select_lex should have item list for correctref_array - allocation. - */ - fake_select_lex->item_list= item_list; + /* + Fake st_select_lex should have item list for correct ref_array + allocation. + */ + fake_select_lex->item_list= item_list; + + /* + We need to add up n_sum_items in order to make the correct + allocation in setup_ref_array(). + Don't add more sum_items if we have already done JOIN::prepare + for this (with a different join object) + */ + if (!fake_select_lex->ref_pointer_array) + fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; + saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, &result_table_list, 0, item_list, NULL, From cfe3489b9577f9736f115c6f4d21055274cf509b Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Fri, 15 Jul 2011 14:07:38 +0200 Subject: [PATCH 05/10] Bug#12406055 BUFFER OVERFLOW OF VARIABLE 'BUFF' IN STRING::SET_REAL The buffer was simply too small. In 5.5 and trunk, the size is 311 + 31, in 5.1 and below, the size is 331 --- client/sql_string.cc | 6 ++++-- include/m_string.h | 9 +++++++++ mysql-test/r/type_float.result | 12 ++++++++++++ mysql-test/t/type_float.test | 15 +++++++++++++++ sql/sql_string.cc | 6 ++++-- sql/unireg.h | 1 - 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/client/sql_string.cc b/client/sql_string.cc index c9443f68e9c..0c89e1d0bca 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc @@ -119,7 +119,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs) bool String::set(double num,uint decimals, CHARSET_INFO *cs) { - char buff[331]; + char buff[FLOATING_POINT_BUFFER]; uint dummy_errors; str_charset=cs; @@ -188,7 +188,9 @@ end: #else #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety - snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num); + int num_chars= snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); + DBUG_ASSERT(num_chars > 0); + DBUG_ASSERT(num_chars < (int) sizeof(buff)); #else sprintf(buff,"%.*f",(int) decimals,num); #endif diff --git a/include/m_string.h b/include/m_string.h index a03254ead11..94de334a050 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -216,6 +216,15 @@ extern int is_prefix(const char *, const char *); double my_strtod(const char *str, char **end, int *error); double my_atof(const char *nptr); +#ifndef NOT_FIXED_DEC +#define NOT_FIXED_DEC 31 +#endif + +/* + Max length of a floating point number. + */ +#define FLOATING_POINT_BUFFER (311 + NOT_FIXED_DEC) + extern char *llstr(longlong value,char *buff); extern char *ullstr(longlong value,char *buff); #ifndef HAVE_STRTOUL diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index d3a136d53d2..c37b77b302d 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -407,4 +407,16 @@ SELECT f1 FROM t1; f1 -1.79769313486231e+308 DROP TABLE t1; +# +# Bug#12406055 BUFFER OVERFLOW OF VARIABLE 'BUFF' IN STRING::SET_REAL +# +select format(-1.7976931348623157E+307,256) as foo; +foo +ignore_float_result +select least(-1.1111111111111111111111111, +- group_concat(1.7976931348623157E+308)) as foo; +foo +ignore_float_result +select concat((truncate((-1.7976931348623157E+307),(0x1e))), +(99999999999999999999999999999999999999999999999999999999999999999)) into @a; End of 5.0 tests diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 3b7b30db6f8..95d6b6d802b 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -276,4 +276,19 @@ INSERT INTO t1 VALUES(-1.79769313486231e+308); SELECT f1 FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#12406055 BUFFER OVERFLOW OF VARIABLE 'BUFF' IN STRING::SET_REAL +--echo # + +let $nine_65= +99999999999999999999999999999999999999999999999999999999999999999; + +--replace_column 1 ignore_float_result +select format(-1.7976931348623157E+307,256) as foo; +--replace_column 1 ignore_float_result +select least(-1.1111111111111111111111111, + - group_concat(1.7976931348623157E+308)) as foo; +eval select concat((truncate((-1.7976931348623157E+307),(0x1e))), + ($nine_65)) into @a; + --echo End of 5.0 tests diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 1c9a3cd7fc2..545643de49f 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -117,7 +117,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs) bool String::set(double num,uint decimals, CHARSET_INFO *cs) { - char buff[331]; + char buff[FLOATING_POINT_BUFFER]; uint dummy_errors; str_charset=cs; @@ -186,7 +186,9 @@ end: #else #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety - snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num); + int num_chars= snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); + DBUG_ASSERT(num_chars > 0); + DBUG_ASSERT(num_chars < (int) sizeof(buff)); #else sprintf(buff,"%.*f",(int) decimals,num); #endif diff --git a/sql/unireg.h b/sql/unireg.h index b5518809527..dd79de0781a 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -175,7 +175,6 @@ */ #define BIN_LOG_HEADER_SIZE 4 -#define FLOATING_POINT_BUFFER 331 #define DEFAULT_KEY_CACHE_NAME "default" From 00f672e677a490a2946e80770ca0d2b217e2cb16 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 18 Jul 2011 09:06:59 +0200 Subject: [PATCH 06/10] Bug#12406055 post-push fix: ignore float output --- mysql-test/r/type_float.result | 5 +---- mysql-test/t/type_float.test | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index c37b77b302d..8c9b3f4b910 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -410,13 +410,10 @@ DROP TABLE t1; # # Bug#12406055 BUFFER OVERFLOW OF VARIABLE 'BUFF' IN STRING::SET_REAL # +# Ignoring output from misc. float operations select format(-1.7976931348623157E+307,256) as foo; -foo -ignore_float_result select least(-1.1111111111111111111111111, - group_concat(1.7976931348623157E+308)) as foo; -foo -ignore_float_result select concat((truncate((-1.7976931348623157E+307),(0x1e))), (99999999999999999999999999999999999999999999999999999999999999999)) into @a; End of 5.0 tests diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 95d6b6d802b..cb929702c0e 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -280,15 +280,17 @@ DROP TABLE t1; --echo # Bug#12406055 BUFFER OVERFLOW OF VARIABLE 'BUFF' IN STRING::SET_REAL --echo # +--echo # Ignoring output from misc. float operations +--disable_result_log + let $nine_65= 99999999999999999999999999999999999999999999999999999999999999999; ---replace_column 1 ignore_float_result select format(-1.7976931348623157E+307,256) as foo; ---replace_column 1 ignore_float_result select least(-1.1111111111111111111111111, - group_concat(1.7976931348623157E+308)) as foo; eval select concat((truncate((-1.7976931348623157E+307),(0x1e))), ($nine_65)) into @a; +--enable_result_log --echo End of 5.0 tests From 01587f5f06dec603c0422c5aa30e615361784348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 10 Aug 2011 14:56:14 +0300 Subject: [PATCH 07/10] Bug#12626794 61240: UNUSED FUNCTIONS ... --- storage/innobase/btr/btr0pcur.c | 27 ------------ storage/innobase/handler/ha_innodb.cc | 19 --------- storage/innobase/include/btr0pcur.h | 19 ++------- storage/innobase/include/btr0pcur.ic | 7 ++-- storage/innobase/include/buf0buf.h | 19 --------- storage/innobase/include/buf0buf.ic | 46 -------------------- storage/innobase/include/mtr0mtr.h | 10 ----- storage/innobase/include/ut0mem.h | 37 ---------------- storage/innobase/include/ut0mem.ic | 21 ---------- storage/innobase/mtr/mtr0mtr.c | 34 --------------- storage/innobase/ut/ut0mem.c | 47 --------------------- storage/innodb_plugin/btr/btr0pcur.c | 29 +------------ storage/innodb_plugin/handler/ha_innodb.cc | 21 +--------- storage/innodb_plugin/include/btr0pcur.h | 21 ++-------- storage/innodb_plugin/include/btr0pcur.ic | 9 ++-- storage/innodb_plugin/include/mtr0mtr.h | 12 +----- storage/innodb_plugin/include/ut0mem.h | 39 +---------------- storage/innodb_plugin/include/ut0mem.ic | 23 +--------- storage/innodb_plugin/mtr/mtr0mtr.c | 36 +--------------- storage/innodb_plugin/ut/ut0mem.c | 49 +--------------------- 20 files changed, 21 insertions(+), 504 deletions(-) diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index f73e82fb597..8d473794243 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -339,33 +339,6 @@ btr_pcur_restore_position( return(FALSE); } -/****************************************************************** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ - -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /* in: persistent cursor */ - mtr_t* mtr) /* in: mtr */ -{ - page_t* page; - - ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - - page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor)); - - btr_leaf_page_release(page, cursor->latch_mode, mtr); - - cursor->latch_mode = BTR_NO_LATCHES; - - cursor->pos_state = BTR_PCUR_WAS_POSITIONED; -} - /************************************************************* Moves the persistent cursor to the first record on the next page. Releases the latch on the current page, and bufferunfixes it. Note that there must not be diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index dfe13ccbbfe..2d230e1c297 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3082,25 +3082,6 @@ field_in_record_is_null( return(0); } -/****************************************************************** -Sets a field in a record to SQL NULL. Uses the record format -information in table to track the null bit in record. */ -inline -void -set_field_in_record_to_null( -/*========================*/ - TABLE* table, /* in: MySQL table object */ - Field* field, /* in: MySQL field object */ - char* record) /* in: a row in MySQL format */ -{ - int null_offset; - - null_offset = (uint) ((char*) field->null_ptr - - (char*) table->record[0]); - - record[null_offset] = record[null_offset] | field->null_bit; -} - extern "C" { /***************************************************************** InnoDB uses this function to compare two data fields for which the data type diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index ee40e905544..95564fd18ce 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -210,18 +210,6 @@ btr_pcur_restore_position( ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /* in: detached persistent cursor */ mtr_t* mtr); /* in: mtr */ -/****************************************************************** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ - -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /* in: persistent cursor */ - mtr_t* mtr); /* in: mtr */ /************************************************************* Gets the rel_pos field for a cursor whose position has been stored. */ UNIV_INLINE @@ -248,10 +236,9 @@ btr_pcur_get_mtr( btr_pcur_t* cursor); /* in: persistent cursor */ /****************************************************************** Commits the pcur mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit( diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 66462530716..ddb37b51eef 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -376,10 +376,9 @@ btr_pcur_move_to_next( /****************************************************************** Commits the pcur mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit( diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7479ce9cbf0..b2adde9cbf4 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -176,25 +176,6 @@ buf_page_optimistic_get_func( ulint line, /* in: line where called */ mtr_t* mtr); /* in: mini-transaction */ /************************************************************************ -Tries to get the page, but if file io is required, releases all latches -in mtr down to the given savepoint. If io is required, this function -retrieves the page to buffer buf_pool, but does not bufferfix it or latch -it. */ -UNIV_INLINE -buf_frame_t* -buf_page_get_release_on_io( -/*=======================*/ - /* out: pointer to the frame, or NULL - if not in buffer buf_pool */ - ulint space, /* in: space id */ - ulint offset, /* in: offset of the page within space - in units of a page */ - buf_frame_t* guess, /* in: guessed frame or NULL */ - ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH, - or RW_NO_LATCH */ - ulint savepoint, /* in: mtr savepoint */ - mtr_t* mtr); /* in: mtr */ -/************************************************************************ This is used to get access to a known database page, when no waiting can be done. */ diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index f4d3619f73f..2d42925faff 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -560,52 +560,6 @@ buf_page_hash_get( return(block); } -/************************************************************************ -Tries to get the page, but if file io is required, releases all latches -in mtr down to the given savepoint. If io is required, this function -retrieves the page to buffer buf_pool, but does not bufferfix it or latch -it. */ -UNIV_INLINE -buf_frame_t* -buf_page_get_release_on_io( -/*=======================*/ - /* out: pointer to the frame, or NULL - if not in buffer buf_pool */ - ulint space, /* in: space id */ - ulint offset, /* in: offset of the page within space - in units of a page */ - buf_frame_t* guess, /* in: guessed frame or NULL */ - ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH, - or RW_NO_LATCH */ - ulint savepoint, /* in: mtr savepoint */ - mtr_t* mtr) /* in: mtr */ -{ - buf_frame_t* frame; - - frame = buf_page_get_gen(space, offset, rw_latch, guess, - BUF_GET_IF_IN_POOL, - __FILE__, __LINE__, - mtr); - if (frame != NULL) { - - return(frame); - } - - /* The page was not in the buffer buf_pool: release the latches - down to the savepoint */ - - mtr_rollback_to_savepoint(mtr, savepoint); - - buf_page_get(space, offset, RW_S_LATCH, mtr); - - /* When we get here, the page is in buffer, but we release - the latches again down to the savepoint, before returning */ - - mtr_rollback_to_savepoint(mtr, savepoint); - - return(NULL); -} - /************************************************************************ Decrements the bufferfix count of a buffer control block and releases a latch, if specified. */ diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index a6e2976830b..2b41fa0059a 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -176,16 +176,6 @@ mtr_set_savepoint( /* out: savepoint */ mtr_t* mtr); /* in: mtr */ /************************************************************** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ - -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /* in: mtr */ - ulint savepoint); /* in: savepoint */ -/************************************************************** Releases the (index tree) s-latch stored in an mtr memo after a savepoint. */ UNIV_INLINE diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index e56895bc142..cb369e85c39 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -144,43 +144,6 @@ ut_strlcpy_rev( const char* src, /* in: source buffer */ ulint size); /* in: size of destination buffer */ -/************************************************************************** -Compute strlen(ut_strcpyq(str, q)). */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - /* out: length of the string when quoted */ - const char* str, /* in: null-terminated string */ - char q); /* in: the quote character */ - -/************************************************************************** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). */ - -char* -ut_strcpyq( -/*=======*/ - /* out: pointer to end of dest */ - char* dest, /* in: output buffer */ - char q, /* in: the quote character */ - const char* src); /* in: null-terminated string */ - -/************************************************************************** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). */ - -char* -ut_memcpyq( -/*=======*/ - /* out: pointer to end of dest */ - char* dest, /* in: output buffer */ - char q, /* in: the quote character */ - const char* src, /* in: string to be quoted */ - ulint len); /* in: length of src */ - /************************************************************************** Return the number of times s2 occurs in s1. Overlapping instances of s2 are only counted once. */ diff --git a/storage/innobase/include/ut0mem.ic b/storage/innobase/include/ut0mem.ic index e0253ebf618..39713352a69 100644 --- a/storage/innobase/include/ut0mem.ic +++ b/storage/innobase/include/ut0mem.ic @@ -47,24 +47,3 @@ ut_strcmp(const void* str1, const void* str2) { return(strcmp((const char*)str1, (const char*)str2)); } - -/************************************************************************** -Compute strlen(ut_strcpyq(str, q)). */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - /* out: length of the string when quoted */ - const char* str, /* in: null-terminated string */ - char q) /* in: the quote character */ -{ - ulint len; - - for (len = 0; *str; len++, str++) { - if (*str == q) { - len++; - } - } - - return(len); -} diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 365fa15878a..728c37ce564 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -201,40 +201,6 @@ mtr_commit( dyn_array_free(&(mtr->log)); } -/************************************************************** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ - -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /* in: mtr */ - ulint savepoint) /* in: savepoint */ -{ - mtr_memo_slot_t* slot; - dyn_array_t* memo; - ulint offset; - - ut_ad(mtr); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - memo = &(mtr->memo); - - offset = dyn_array_get_data_size(memo); - ut_ad(offset >= savepoint); - - while (offset > savepoint) { - offset -= sizeof(mtr_memo_slot_t); - - slot = dyn_array_get_element(memo, offset); - - ut_ad(slot->type != MTR_MEMO_MODIFY); - mtr_memo_slot_release(mtr, slot); - } -} - /******************************************************* Releases an object in the memo stack. */ diff --git a/storage/innobase/ut/ut0mem.c b/storage/innobase/ut/ut0mem.c index b466a5f6872..2e0dd27edf4 100644 --- a/storage/innobase/ut/ut0mem.c +++ b/storage/innobase/ut/ut0mem.c @@ -407,53 +407,6 @@ ut_strlcpy_rev( return(src_size); } -/************************************************************************** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). */ - -char* -ut_strcpyq( -/*=======*/ - /* out: pointer to end of dest */ - char* dest, /* in: output buffer */ - char q, /* in: the quote character */ - const char* src) /* in: null-terminated string */ -{ - while (*src) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - -/************************************************************************** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). */ - -char* -ut_memcpyq( -/*=======*/ - /* out: pointer to end of dest */ - char* dest, /* in: output buffer */ - char q, /* in: the quote character */ - const char* src, /* in: string to be quoted */ - ulint len) /* in: length of src */ -{ - const char* srcend = src + len; - - while (src < srcend) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - /************************************************************************** Return the number of times s2 occurs in s1. Overlapping instances of s2 are only counted once. */ diff --git a/storage/innodb_plugin/btr/btr0pcur.c b/storage/innodb_plugin/btr/btr0pcur.c index 056896c7927..e3e3e53f98e 100644 --- a/storage/innodb_plugin/btr/btr0pcur.c +++ b/storage/innodb_plugin/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 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 @@ -356,33 +356,6 @@ btr_pcur_restore_position_func( return(FALSE); } -/**************************************************************//** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ -UNIV_INTERN -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr) /*!< in: mtr */ -{ - buf_block_t* block; - - ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - - block = btr_pcur_get_block(cursor); - - btr_leaf_page_release(block, cursor->latch_mode, mtr); - - cursor->latch_mode = BTR_NO_LATCHES; - - cursor->pos_state = BTR_PCUR_WAS_POSITIONED; -} - /*********************************************************//** Moves the persistent cursor to the first record on the next page. Releases the latch on the current page, and bufferunfixes it. Note that there must not be diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 609299efce5..aec0e77768c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -3792,25 +3792,6 @@ field_in_record_is_null( return(0); } -/**************************************************************//** -Sets a field in a record to SQL NULL. Uses the record format -information in table to track the null bit in record. */ -static inline -void -set_field_in_record_to_null( -/*========================*/ - TABLE* table, /*!< in: MySQL table object */ - Field* field, /*!< in: MySQL field object */ - char* record) /*!< in: a row in MySQL format */ -{ - int null_offset; - - null_offset = (uint) ((char*) field->null_ptr - - (char*) table->record[0]); - - record[null_offset] = record[null_offset] | field->null_bit; -} - /*************************************************************//** InnoDB uses this function to compare two data fields for which the data type is such that we must use MySQL code to compare them. NOTE that the prototype diff --git a/storage/innodb_plugin/include/btr0pcur.h b/storage/innodb_plugin/include/btr0pcur.h index 2334a266280..f59514d04b3 100644 --- a/storage/innodb_plugin/include/btr0pcur.h +++ b/storage/innodb_plugin/include/btr0pcur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 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 @@ -244,18 +244,6 @@ btr_pcur_restore_position_func( mtr_t* mtr); /*!< in: mtr */ #define btr_pcur_restore_position(l,cur,mtr) \ btr_pcur_restore_position_func(l,cur,__FILE__,__LINE__,mtr) -/**************************************************************//** -If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, -releases the page latch and bufferfix reserved by the cursor. -NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes -made by the current mini-transaction to the data protected by the -cursor latch, as then the latch must not be released until mtr_commit. */ -UNIV_INTERN -void -btr_pcur_release_leaf( -/*==================*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr); /*!< in: mtr */ /*********************************************************//** Gets the rel_pos field for a cursor whose position has been stored. @return BTR_PCUR_ON, ... */ @@ -282,10 +270,9 @@ btr_pcur_get_mtr( btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit_specify_mtr( diff --git a/storage/innodb_plugin/include/btr0pcur.ic b/storage/innodb_plugin/include/btr0pcur.ic index 0c38797e6c5..0f9b969e7c5 100644 --- a/storage/innodb_plugin/include/btr0pcur.ic +++ b/storage/innodb_plugin/include/btr0pcur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 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 @@ -396,10 +396,9 @@ btr_pcur_move_to_next( /**************************************************************//** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, -that is, the cursor becomes detached. If there have been modifications -to the page where pcur is positioned, this can be used instead of -btr_pcur_release_leaf. Function btr_pcur_store_position should be used -before calling this, if restoration of cursor is wanted later. */ +that is, the cursor becomes detached. +Function btr_pcur_store_position should be used before calling this, +if restoration of cursor is wanted later. */ UNIV_INLINE void btr_pcur_commit_specify_mtr( diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index bc3f1951be9..8a9ec8ea7f0 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 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 @@ -213,16 +213,6 @@ ulint mtr_set_savepoint( /*==============*/ mtr_t* mtr); /*!< in: mtr */ -/**********************************************************//** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ -UNIV_INTERN -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint savepoint); /*!< in: savepoint */ #ifndef UNIV_HOTBACKUP /**********************************************************//** Releases the (index tree) s-latch stored in an mtr memo after a diff --git a/storage/innodb_plugin/include/ut0mem.h b/storage/innodb_plugin/include/ut0mem.h index f14606be966..9c6ee9049ec 100644 --- a/storage/innodb_plugin/include/ut0mem.h +++ b/storage/innodb_plugin/include/ut0mem.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 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 @@ -209,43 +209,6 @@ ut_strlcpy_rev( const char* src, /*!< in: source buffer */ ulint size); /*!< in: size of destination buffer */ -/**********************************************************************//** -Compute strlen(ut_strcpyq(str, q)). -@return length of the string when quoted */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - const char* str, /*!< in: null-terminated string */ - char q); /*!< in: the quote character */ - -/**********************************************************************//** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_strcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src); /*!< in: null-terminated string */ - -/**********************************************************************//** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_memcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src, /*!< in: string to be quoted */ - ulint len); /*!< in: length of src */ - /**********************************************************************//** Return the number of times s2 occurs in s1. Overlapping instances of s2 are only counted once. diff --git a/storage/innodb_plugin/include/ut0mem.ic b/storage/innodb_plugin/include/ut0mem.ic index f36c28f1989..c06e2b3ae81 100644 --- a/storage/innodb_plugin/include/ut0mem.ic +++ b/storage/innodb_plugin/include/ut0mem.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 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 @@ -98,27 +98,6 @@ ut_strcmp(const char* str1, const char* str2) return(strcmp(str1, str2)); } -/**********************************************************************//** -Compute strlen(ut_strcpyq(str, q)). -@return length of the string when quoted */ -UNIV_INLINE -ulint -ut_strlenq( -/*=======*/ - const char* str, /*!< in: null-terminated string */ - char q) /*!< in: the quote character */ -{ - ulint len; - - for (len = 0; *str; len++, str++) { - if (*str == q) { - len++; - } - } - - return(len); -} - /**********************************************************************//** Converts a raw binary data to a NUL-terminated hex string. The output is truncated if there is not enough space in "hex", make sure "hex_size" is at diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index 417e97732bb..5fad61b2922 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 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 @@ -211,40 +211,6 @@ mtr_commit( } #ifndef UNIV_HOTBACKUP -/**********************************************************//** -Releases the latches stored in an mtr memo down to a savepoint. -NOTE! The mtr must not have made changes to buffer pages after the -savepoint, as these can be handled only by mtr_commit. */ -UNIV_INTERN -void -mtr_rollback_to_savepoint( -/*======================*/ - mtr_t* mtr, /*!< in: mtr */ - ulint savepoint) /*!< in: savepoint */ -{ - mtr_memo_slot_t* slot; - dyn_array_t* memo; - ulint offset; - - ut_ad(mtr); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - memo = &(mtr->memo); - - offset = dyn_array_get_data_size(memo); - ut_ad(offset >= savepoint); - - while (offset > savepoint) { - offset -= sizeof(mtr_memo_slot_t); - - slot = dyn_array_get_element(memo, offset); - - ut_ad(slot->type != MTR_MEMO_MODIFY); - mtr_memo_slot_release(mtr, slot); - } -} - /***************************************************//** Releases an object in the memo stack. */ UNIV_INTERN diff --git a/storage/innodb_plugin/ut/ut0mem.c b/storage/innodb_plugin/ut/ut0mem.c index bf55e4273b6..95fb2187b79 100644 --- a/storage/innodb_plugin/ut/ut0mem.c +++ b/storage/innodb_plugin/ut/ut0mem.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 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 @@ -489,53 +489,6 @@ ut_strlcpy_rev( return(src_size); } -/**********************************************************************//** -Make a quoted copy of a NUL-terminated string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_memcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_strcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src) /*!< in: null-terminated string */ -{ - while (*src) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - -/**********************************************************************//** -Make a quoted copy of a fixed-length string. Leading and trailing -quotes will not be included; only embedded quotes will be escaped. -See also ut_strlenq() and ut_strcpyq(). -@return pointer to end of dest */ -UNIV_INTERN -char* -ut_memcpyq( -/*=======*/ - char* dest, /*!< in: output buffer */ - char q, /*!< in: the quote character */ - const char* src, /*!< in: string to be quoted */ - ulint len) /*!< in: length of src */ -{ - const char* srcend = src + len; - - while (src < srcend) { - if ((*dest++ = *src++) == q) { - *dest++ = q; - } - } - - return(dest); -} - #ifndef UNIV_HOTBACKUP /**********************************************************************//** Return the number of times s2 occurs in s1. Overlapping instances of s2 From 1ebc1e07038aa32e43dd5e0807559a4998b160ef Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 16 Sep 2011 15:30:31 +0400 Subject: [PATCH 08/10] BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES myisamchk may create incorrect fulltext index for compressed tables. Incorrect data pointer size was used while creating fulltext index. --- mysql-test/r/myisampack.result | 32 +++++++++++++++++++++ mysql-test/t/myisampack.test | 45 ++++++++++++++++++++++++++++++ storage/myisam/ft_boolean_search.c | 2 +- storage/myisam/ft_nlq_search.c | 2 +- storage/myisam/mi_check.c | 4 +-- storage/myisam/mi_write.c | 2 +- 6 files changed, 82 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result index fbcd8aed17a..f19a9c49427 100644 --- a/mysql-test/r/myisampack.result +++ b/mysql-test/r/myisampack.result @@ -87,3 +87,35 @@ COUNT(*) 128 DROP TABLE mysql_db1.t1; DROP DATABASE mysql_db1; +# +# BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES +# +CREATE TABLE t1(a CHAR(4), FULLTEXT(a)); +INSERT INTO t1 VALUES('aaaa'),('bbbb'),('cccc'); +FLUSH TABLE t1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa' IN BOOLEAN MODE); +a +aaaa +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa'); +a +aaaa +DROP TABLE t1; +# Test table with key_reflength > rec_reflength +CREATE TABLE t1(a CHAR(30), FULLTEXT(a)); +# Populating a table, so it's index file exceeds 65K +# Populating a table, so index file has second level fulltext tree +FLUSH TABLE t1; +# Compressing table +# Fixing index (repair by sort) +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +FLUSH TABLE t1; +# Fixing index (repair with keycache) +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test index 9d27ed53254..3bce8cfcfb8 100644 --- a/mysql-test/t/myisampack.test +++ b/mysql-test/t/myisampack.test @@ -107,3 +107,48 @@ SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5; # DROP TABLE mysql_db1.t1; DROP DATABASE mysql_db1; + +--echo # +--echo # BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES +--echo # +CREATE TABLE t1(a CHAR(4), FULLTEXT(a)); +INSERT INTO t1 VALUES('aaaa'),('bbbb'),('cccc'); +FLUSH TABLE t1; +--exec $MYISAMPACK -sf $MYSQLD_DATADIR/test/t1 +--exec $MYISAMCHK -srq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa' IN BOOLEAN MODE); +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa'); +DROP TABLE t1; + +--echo # Test table with key_reflength > rec_reflength +CREATE TABLE t1(a CHAR(30), FULLTEXT(a)); +--disable_query_log +--echo # Populating a table, so it's index file exceeds 65K +let $1=1700; +while ($1) +{ + eval INSERT INTO t1 VALUES('$1aaaaaaaaaaaaaaaaaaaaaaaaaa'); + dec $1; +} + +--echo # Populating a table, so index file has second level fulltext tree +let $1=60; +while ($1) +{ + eval INSERT INTO t1 VALUES('aaaa'),('aaaa'),('aaaa'),('aaaa'),('aaaa'); + dec $1; +} +--enable_query_log + +FLUSH TABLE t1; +--echo # Compressing table +--exec $MYISAMPACK -sf $MYSQLD_DATADIR/test/t1 +--echo # Fixing index (repair by sort) +--exec $MYISAMCHK -srnq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +FLUSH TABLE t1; +--echo # Fixing index (repair with keycache) +--exec $MYISAMCHK -soq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +DROP TABLE t1; diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index fb1a03a2bd6..ac5da800ae3 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -361,7 +361,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) int subkeys=1; my_bool can_go_down; MI_INFO *info=ftb->info; - uint UNINIT_VAR(off), extra=HA_FT_WLEN+info->s->base.rec_reflength; + uint UNINIT_VAR(off), extra= HA_FT_WLEN + info->s->rec_reflength; uchar *lastkey_buf=ftbw->word+ftbw->off; if (ftbw->flags & FTB_FLAG_TRUNC) diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c index cd2c7f61a66..567b1044995 100644 --- a/storage/myisam/ft_nlq_search.c +++ b/storage/myisam/ft_nlq_search.c @@ -74,7 +74,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; my_off_t key_root=info->s->state.key_root[aio->keynr]; - uint extra=HA_FT_WLEN+info->s->base.rec_reflength; + uint extra= HA_FT_WLEN + info->s->rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; #else diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 3bbd2fb0469..4a0c2da5559 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -3913,7 +3913,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) SORT_FT_BUF *ft_buf=sort_info->ft_buf; SORT_KEY_BLOCKS *key_block=sort_info->key_block; - val_len=HA_FT_WLEN+sort_info->info->s->base.rec_reflength; + val_len= HA_FT_WLEN + sort_info->info->s->rec_reflength; get_key_full_length_rdonly(a_len, (uchar *)a); if (!ft_buf) @@ -3923,7 +3923,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) and row format is NOT static - for _mi_dpointer not to garble offsets */ if ((sort_info->info->s->base.key_reflength <= - sort_info->info->s->base.rec_reflength) && + sort_info->info->s->rec_reflength) && (sort_info->info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) ft_buf=(SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length + diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c index 70487f397f1..81262c229ce 100644 --- a/storage/myisam/mi_write.c +++ b/storage/myisam/mi_write.c @@ -528,7 +528,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (keyinfo->block_length - a_length < 32 && keyinfo->flag & HA_FULLTEXT && key_pos == endpos && - info->s->base.key_reflength <= info->s->base.rec_reflength && + info->s->base.key_reflength <= info->s->rec_reflength && info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) { /* From 8d036bcd61ff8993126c229fd7203abe63f0f625 Mon Sep 17 00:00:00 2001 From: "kevin.lewis@oracle.com" <> Date: Tue, 20 Sep 2011 18:12:36 -0600 Subject: [PATCH 09/10] Bug 12963823 - Crash in Purge thread under unusual circumstances. The problem occurred when indexes are added between the time that an UNDO record is created and the time that the purge thread comes around and deletes the old secondary index entries. The purge thread would hit an assert when trying to build a secondary index entry for searching. The problem was that the old value of those fields were not in the UNDO record since they were not part of an index when the UPDATE occured. A test case was added to innodb-index.test. --- .../suite/innodb_plugin/r/innodb-index.result | 91 ++++++++++++++++--- .../suite/innodb_plugin/t/innodb-index.test | 87 ++++++++++++++---- storage/innodb_plugin/row/row0purge.c | 17 ++-- 3 files changed, 154 insertions(+), 41 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index 5be1460d2b7..8640ff94d9e 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -39,6 +39,81 @@ DELETE FROM t1_purge; DELETE FROM t2_purge; DELETE FROM t3_purge; DELETE FROM t4_purge; +SET @r=REPEAT('a',500); +CREATE TABLE t12637786(a INT, +v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), +v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), +v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), +v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), +v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), +v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE INDEX idx1 ON t12637786(a,v1); +INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t12637786 SET a=1000; +DELETE FROM t12637786; +create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, +i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob) +engine=innodb row_format=dynamic; +SET @r = repeat('a', 767); +insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r); +create index ndx_a on t12963823 (a(500)); +create index ndx_b on t12963823 (b(500)); +create index ndx_c on t12963823 (c(500)); +create index ndx_d on t12963823 (d(500)); +create index ndx_e on t12963823 (e(500)); +create index ndx_f on t12963823 (f(500)); +create index ndx_k on t12963823 (k(500)); +create index ndx_l on t12963823 (l(500)); +SET @r = repeat('b', 500); +update t12963823 set a=@r,b=@r,c=@r,d=@r; +update t12963823 set e=@r,f=@r,g=@r,h=@r; +update t12963823 set i=@r,j=@r,k=@r,l=@r; +update t12963823 set m=@r,n=@r,o=@r,p=@r; +alter table t12963823 drop index ndx_a; +alter table t12963823 drop index ndx_b; +create index ndx_g on t12963823 (g(500)); +create index ndx_h on t12963823 (h(500)); +create index ndx_i on t12963823 (i(500)); +create index ndx_j on t12963823 (j(500)); +create index ndx_m on t12963823 (m(500)); +create index ndx_n on t12963823 (n(500)); +create index ndx_o on t12963823 (o(500)); +create index ndx_p on t12963823 (p(500)); +show create table t12963823; +Table Create Table +t12963823 CREATE TABLE `t12963823` ( + `a` blob, + `b` blob, + `c` blob, + `d` blob, + `e` blob, + `f` blob, + `g` blob, + `h` blob, + `i` blob, + `j` blob, + `k` blob, + `l` blob, + `m` blob, + `n` blob, + `o` blob, + `p` blob, + KEY `ndx_c` (`c`(500)), + KEY `ndx_d` (`d`(500)), + KEY `ndx_e` (`e`(500)), + KEY `ndx_f` (`f`(500)), + KEY `ndx_k` (`k`(500)), + KEY `ndx_l` (`l`(500)), + KEY `ndx_g` (`g`(500)), + KEY `ndx_h` (`h`(500)), + KEY `ndx_i` (`i`(500)), + KEY `ndx_j` (`j`(500)), + KEY `ndx_m` (`m`(500)), + KEY `ndx_n` (`n`(500)), + KEY `ndx_o` (`o`(500)), + KEY `ndx_p` (`p`(500)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC set global innodb_file_per_table=0; set global innodb_file_format=Antelope; create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; @@ -1010,20 +1085,6 @@ ERROR HY000: Too big row alter table t1 row_format=compact; create index t1u on t1 (u(1)); drop table t1; -SET @r=REPEAT('a',500); -CREATE TABLE t1(a INT, -v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), -v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), -v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), -v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), -v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), -v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -CREATE INDEX idx1 ON t1(a,v1); -INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); -UPDATE t1 SET a=1000; -DELETE FROM t1; -DROP TABLE t1; CREATE TABLE bug12547647( a INT NOT NULL, b BLOB NOT NULL, c TEXT, PRIMARY KEY (b(10), a), INDEX (c(10)) @@ -1237,3 +1298,5 @@ a b 3 b DROP TABLE t1; DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; +DROP TABLE t12637786; +DROP TABLE t12963823; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index b4e2aae09e9..a671b48a9c1 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -9,7 +9,7 @@ let $format=`select @@innodb_file_format`; set global innodb_file_per_table=on; set global innodb_file_format='Barracuda'; -# Test an assertion failure on purge. +# Bug #12429576 - Test an assertion failure on purge. CREATE TABLE t1_purge ( A INT, B BLOB, C BLOB, D BLOB, E BLOB, @@ -59,6 +59,68 @@ DELETE FROM t1_purge; DELETE FROM t2_purge; DELETE FROM t3_purge; DELETE FROM t4_purge; +# Instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the tables. By then, the purge thread +# will have delt with the updates above. + +# Bug#12637786 - Bad assert by purge thread for records with external data +# used in secondary indexes. +SET @r=REPEAT('a',500); +CREATE TABLE t12637786(a INT, + v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), + v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), + v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), + v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), + v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), + v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE INDEX idx1 ON t12637786(a,v1); +INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t12637786 SET a=1000; +DELETE FROM t12637786; +# We need to activate the purge thread at this point to make sure it does not +# assert and is able to clean up the old versions of secondary index entries. +# But instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the table. By then, the purge thread +# will have delt with the updates above. + +# Bug#12963823 - Test that the purge thread does not crash when +# the number of indexes has changed since the UNDO record was logged. +create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, + i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob) + engine=innodb row_format=dynamic; +SET @r = repeat('a', 767); +insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r); +create index ndx_a on t12963823 (a(500)); +create index ndx_b on t12963823 (b(500)); +create index ndx_c on t12963823 (c(500)); +create index ndx_d on t12963823 (d(500)); +create index ndx_e on t12963823 (e(500)); +create index ndx_f on t12963823 (f(500)); +create index ndx_k on t12963823 (k(500)); +create index ndx_l on t12963823 (l(500)); + +SET @r = repeat('b', 500); +update t12963823 set a=@r,b=@r,c=@r,d=@r; +update t12963823 set e=@r,f=@r,g=@r,h=@r; +update t12963823 set i=@r,j=@r,k=@r,l=@r; +update t12963823 set m=@r,n=@r,o=@r,p=@r; +alter table t12963823 drop index ndx_a; +alter table t12963823 drop index ndx_b; +create index ndx_g on t12963823 (g(500)); +create index ndx_h on t12963823 (h(500)); +create index ndx_i on t12963823 (i(500)); +create index ndx_j on t12963823 (j(500)); +create index ndx_m on t12963823 (m(500)); +create index ndx_n on t12963823 (n(500)); +create index ndx_o on t12963823 (o(500)); +create index ndx_p on t12963823 (p(500)); +show create table t12963823; +# We need to activate the purge thread at this point to see if it crashes +# but instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the table. By then, the purge thread +# will have delt with the updates above. + eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; @@ -462,24 +524,6 @@ create index t1u on t1 (u(1)); drop table t1; -# Bug#12637786 -SET @r=REPEAT('a',500); -CREATE TABLE t1(a INT, - v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), - v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), - v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), - v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), - v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), - v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -CREATE INDEX idx1 ON t1(a,v1); -INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); -UPDATE t1 SET a=1000; -DELETE FROM t1; -# Let the purge thread clean up this file. --- sleep 10 -DROP TABLE t1; - # Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE CREATE TABLE bug12547647( a INT NOT NULL, b BLOB NOT NULL, c TEXT, @@ -630,7 +674,12 @@ disconnect a; disconnect b; DROP TABLE t1; + +# Drop these tables since the purge thread must have run by now +# and did not crash. DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; +DROP TABLE t12637786; +DROP TABLE t12963823; # # restore environment to the state it was before this test execution diff --git a/storage/innodb_plugin/row/row0purge.c b/storage/innodb_plugin/row/row0purge.c index 752a2ec9e83..e1df40978a4 100644 --- a/storage/innodb_plugin/row/row0purge.c +++ b/storage/innodb_plugin/row/row0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 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 @@ -11,8 +11,8 @@ 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 +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -530,14 +530,14 @@ row_purge_parse_undo_rec( roll_ptr_t roll_ptr; ulint info_bits; ulint type; - ulint cmpl_info; ut_ad(node && thr); trx = thr_get_trx(thr); - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, - updated_extern, &undo_no, &table_id); + ptr = trx_undo_rec_get_pars( + node->undo_rec, &type, &node->cmpl_info, + updated_extern, &undo_no, &table_id); node->rec_type = type; if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { @@ -550,7 +550,8 @@ row_purge_parse_undo_rec( node->table = NULL; if (type == TRX_UNDO_UPD_EXIST_REC - && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { + && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE + && !(*updated_extern)) { /* Purge requires no changes to indexes: we may return */ @@ -600,7 +601,7 @@ err_exit: /* Read to the partial row the fields that occur in indexes */ - if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { ptr = trx_undo_rec_get_partial_row( ptr, clust_index, &node->row, type == TRX_UNDO_UPD_DEL_REC, From 5c57f8cc9be2c49131fee71a2be9e55b46a9f471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Sep 2011 13:35:02 +0300 Subject: [PATCH 10/10] Bug#12963823 CRASH IN PURGE THREAD UNDER UNUSUAL CIRCUMSTANCES Replace part of the patch that Kevin apparently forgot to push. Fix the bug also in the built-in InnoDB of MySQL 5.1. I cannot explain why the test case was not failing without the full patch. This was rb:762, approved by me. --- storage/innobase/row/row0purge.c | 14 ++++++++------ storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/row/row0purge.c | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index deec3b0a454..506d92f052e 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -379,7 +379,8 @@ row_purge_upd_exist_or_extern( ut_ad(node); - if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { + if (node->rec_type == TRX_UNDO_UPD_DEL_REC + || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto skip_secondaries; } @@ -488,14 +489,14 @@ row_purge_parse_undo_rec( dulint roll_ptr; ulint info_bits; ulint type; - ulint cmpl_info; ut_ad(node && thr); trx = thr_get_trx(thr); - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, - updated_extern, &undo_no, &table_id); + ptr = trx_undo_rec_get_pars( + node->undo_rec, &type, &node->cmpl_info, + updated_extern, &undo_no, &table_id); node->rec_type = type; if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { @@ -508,7 +509,8 @@ row_purge_parse_undo_rec( node->table = NULL; if (type == TRX_UNDO_UPD_EXIST_REC - && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { + && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE + && !(*updated_extern)) { /* Purge requires no changes to indexes: we may return */ @@ -563,7 +565,7 @@ row_purge_parse_undo_rec( /* Read to the partial row the fields that occur in indexes */ - if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { ptr = trx_undo_rec_get_partial_row(ptr, clust_index, &(node->row), node->heap); } diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index ff6bd10dbe6..171f1edd7ba 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-20 The InnoDB Team + + * row/row0purge.c: + Fix Bug#12963823 CRASH IN PURGE THREAD UNDER UNUSUAL CIRCUMSTANCES + 2011-09-12 The InnoDB Team * row/row0sel.c: diff --git a/storage/innodb_plugin/row/row0purge.c b/storage/innodb_plugin/row/row0purge.c index e1df40978a4..4d4c1afc458 100644 --- a/storage/innodb_plugin/row/row0purge.c +++ b/storage/innodb_plugin/row/row0purge.c @@ -406,7 +406,8 @@ row_purge_upd_exist_or_extern_func( ut_ad(node); - if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { + if (node->rec_type == TRX_UNDO_UPD_DEL_REC + || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto skip_secondaries; }