From 70fbfa0ce2f3310f2a80e424e0d96ff8234ed91b Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 8 Jul 2011 16:25:32 +0200 Subject: [PATCH 001/143] Fix Bug #47337: innochecksum not built for --with-plugin-innodb_plugin --without-plugin-innobase In 5.1, we can have the traditional "innobase" code (built-in) or the new version "innodb" (plugin). The help tool "innochecksum" is useful for both, but its generation was coupled to "innobase" only. Fix this by treating both "innobase" and "innodb" equivalent in the configure phase, this affects both "innochecksum" and the InnoDB documentation. This patch was proposed by Mark Callaghan. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 0948fe1349d..fffbde0fd00 100644 --- a/configure.in +++ b/configure.in @@ -2711,7 +2711,7 @@ then MAN_DROP="$MAN_DROP embedded" grep -v 'embedded' $MANLISTFIL > $TMPLISTFIL ; mv -f $TMPLISTFIL $MANLISTFIL fi - if test X"$with_plugin_innobase" != Xyes + if test X"$with_plugin_innobase" != Xyes -a X"$with_plugin_innodb_plugin" != Xyes then MAN_DROP="$MAN_DROP innodb" grep -v 'inno' $MANLISTFIL > $TMPLISTFIL ; mv -f $TMPLISTFIL $MANLISTFIL @@ -2790,7 +2790,7 @@ then fi # "innochecksum" is not in the "innobase/" subdirectory, but should be switched -AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes]) +AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes -o X"$with_plugin_innodb_plugin" = Xyes ]) # IMPORTANT - do not modify LIBS past this line - this hack is the only way # I know to add the static NSS magic if we have static NSS libraries with From 083a316d1f9020d48a5b9769fafbb3accad3c03a Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Tue, 12 Jul 2011 06:08:52 +0100 Subject: [PATCH 002/143] Bug#11758414/Bug#50614: Default storage_engine not honored when set from within a stored procedure When CREATE TABLE wasn't given ENGINE=... it would determine the default ENGINE at parse-time rather than at execution time, leading to incorrect behaviour (namely, later changes to the default engine being ignore) when calling CREATE TABLE from a stored procedure. We now defer working out the default engine till execution of CREATE TABLE. mysql-test/r/sp_trans.result: results! mysql-test/t/sp_trans.test: Show that CREATE TABLE (called from store routine) heeds any changes after CREATE SP / parse-time. Show that explicitly requesting an ENGINE still works. sql/sql_parse.cc: If no ENGINE=... was given at parse-time, determine default engine at execution time of CREATE TABLE. sql/sql_yacc.yy: If CREATE TABLE is not given ENGINE=..., don't bother figuring out the default engine during parsing; we'll do it at execution time instead to be aware of the latest updates. --- mysql-test/r/sp_trans.result | 46 ++++++++++++++++++++++++++++++++++++ mysql-test/t/sp_trans.test | 33 ++++++++++++++++++++++++++ sql/sql_parse.cc | 6 +++++ sql/sql_yacc.yy | 4 ++-- 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result index a64f53efde7..dec37db652a 100644 --- a/mysql-test/r/sp_trans.result +++ b/mysql-test/r/sp_trans.result @@ -556,3 +556,49 @@ f1 bug13575(f1) 3 ccc drop function bug13575| drop table t3| +SELECT @@GLOBAL.storage_engine INTO @old_engine| +SET @@GLOBAL.storage_engine=InnoDB| +SET @@SESSION.storage_engine=InnoDB| +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine InnoDB +SHOW SESSION VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine InnoDB +CREATE PROCEDURE bug11758414() +BEGIN +SET @@GLOBAL.storage_engine="MyISAM"; +SET @@SESSION.storage_engine="MyISAM"; +# show defaults at execution time / that setting them worked +SHOW GLOBAL VARIABLES LIKE 'storage_engine'; +SHOW SESSION VARIABLES LIKE 'storage_engine'; +CREATE TABLE t1 (id int); +CREATE TABLE t2 (id int) ENGINE=InnoDB; +# show we're heeding the default (at run-time, not parse-time!) + SHOW CREATE TABLE t1; + # show that we didn't break explicit override with ENGINE=... +SHOW CREATE TABLE t2; +END; +| +CALL bug11758414| +Variable_name Value +storage_engine MyISAM +Variable_name Value +storage_engine MyISAM +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine MyISAM +SHOW SESSION VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine MyISAM +DROP PROCEDURE bug11758414| +DROP TABLE t1, t2| +SET @@GLOBAL.storage_engine=@old_engine| diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test index 0b04b9d7668..2d59fb20bbd 100644 --- a/mysql-test/t/sp_trans.test +++ b/mysql-test/t/sp_trans.test @@ -593,6 +593,39 @@ drop function bug13575| drop table t3| +# +# BUG#11758414: Default storage_engine not honored when set +# from within a stored procedure +# +SELECT @@GLOBAL.storage_engine INTO @old_engine| +SET @@GLOBAL.storage_engine=InnoDB| +SET @@SESSION.storage_engine=InnoDB| +# show defaults at define-time +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +SHOW SESSION VARIABLES LIKE 'storage_engine'| +CREATE PROCEDURE bug11758414() +BEGIN + SET @@GLOBAL.storage_engine="MyISAM"; + SET @@SESSION.storage_engine="MyISAM"; + # show defaults at execution time / that setting them worked + SHOW GLOBAL VARIABLES LIKE 'storage_engine'; + SHOW SESSION VARIABLES LIKE 'storage_engine'; + CREATE TABLE t1 (id int); + CREATE TABLE t2 (id int) ENGINE=InnoDB; + # show we're heeding the default (at run-time, not parse-time!) + SHOW CREATE TABLE t1; + # show that we didn't break explicit override with ENGINE=... + SHOW CREATE TABLE t2; +END; +| +CALL bug11758414| +# show that changing defaults within SP stuck +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +SHOW SESSION VARIABLES LIKE 'storage_engine'| +DROP PROCEDURE bug11758414| +DROP TABLE t1, t2| +SET @@GLOBAL.storage_engine=@old_engine| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2eeabc2f0c1..14ad77d29fd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2616,6 +2616,12 @@ mysql_execute_command(THD *thd) create_table->table_name)) goto end_with_restore_list; #endif + /* + If no engine type was given, work out the default now + rather than at parse-time. + */ + if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) + create_info.db_type= ha_default_handlerton(thd); /* If we are using SET CHARSET without DEFAULT, add an implicit DEFAULT to not confuse old users. (This may change). diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6245f07b9cf..f4fb822b294 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1838,7 +1838,6 @@ create: lex->change=NullS; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.options=$2 | $4; - lex->create_info.db_type= ha_default_handlerton(thd); lex->create_info.default_table_charset= NULL; lex->name.str= 0; lex->name.length= 0; @@ -1847,7 +1846,8 @@ create: { LEX *lex= YYTHD->lex; lex->current_select= &lex->select_lex; - if (!lex->create_info.db_type) + if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && + !lex->create_info.db_type) { lex->create_info.db_type= ha_default_handlerton(YYTHD); push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN, From a38fc8d47e121e15b82e26b5bffecb9c3d5801ee Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 10:17:58 -0400 Subject: [PATCH 003/143] WL#5710 : mysql_plugin - enable or disable plugins This patch adds a new client utility that enables or disables plugin features. The utility disables or enables a plugin using values (name, soname, and symbols) provided via a configuration file by the same name. For example, to ENABLE the daemon_example plugin, the utility will read the daemon_example.ini configuration file and use the values contained to enable or disable the plugin. --- client/CMakeLists.txt | 5 +- client/mysql_plugin.c | 1077 +++++++++++++++++ include/my_global.h | 4 + mysql-test/include/daemon_example.ini | 8 + .../include/daemon_example_bad_format.ini | 8 + mysql-test/include/plugin.defs | 1 + mysql-test/mysql-test-run.pl | 3 + mysql-test/r/mysql_plugin.result | 97 ++ mysql-test/t/mysql_plugin-master.opt | 1 + mysql-test/t/mysql_plugin.test | 205 ++++ plugin/daemon_example/CMakeLists.txt | 2 + plugin/daemon_example/daemon_example.ini | 6 + 12 files changed, 1416 insertions(+), 1 deletion(-) create mode 100644 client/mysql_plugin.c create mode 100644 mysql-test/include/daemon_example.ini create mode 100644 mysql-test/include/daemon_example_bad_format.ini create mode 100644 mysql-test/r/mysql_plugin.result create mode 100644 mysql-test/t/mysql_plugin-master.opt create mode 100644 mysql-test/t/mysql_plugin.test create mode 100644 plugin/daemon_example/daemon_example.ini diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 80c5bbd1c9f..c5bda7d8a35 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -54,6 +54,9 @@ ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) MYSQL_ADD_EXECUTABLE(mysqlshow mysqlshow.c) TARGET_LINK_LIBRARIES(mysqlshow mysqlclient) +MYSQL_ADD_EXECUTABLE(mysql_plugin mysql_plugin.c) +TARGET_LINK_LIBRARIES(mysql_plugin mysqlclient) + MYSQL_ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc) TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient) @@ -69,7 +72,7 @@ IF(WIN32) MYSQL_ADD_EXECUTABLE(echo echo.c) ENDIF(WIN32) -SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap +SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap mysql_plugin PROPERTIES HAS_CXX TRUE) ADD_DEFINITIONS(-DHAVE_DLOPEN) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c new file mode 100644 index 00000000000..ca3da0086e4 --- /dev/null +++ b/client/mysql_plugin.c @@ -0,0 +1,1077 @@ +/* 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 +*/ + +#include +#include +#include +#include +#include +#include +#include + + +#define SHOW_VERSION "1.0.0" +#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \ + my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \ + } while(0) + +/* Global variables. */ +static uint my_end_arg= 0; +static uint opt_verbose=0; +static uint opt_no_defaults= 0; +static uint opt_print_defaults= 0; +static char *opt_datadir=0, *opt_basedir=0, + *opt_plugin_dir=0, *opt_plugin_ini=0; +static char bootstrap[FN_REFLEN]; + + +/* plugin struct */ +struct st_plugin +{ + const char *name; /* plugin name */ + const char *so_name; /* plugin so (library) name */ + const char *symbols[16]; /* symbols to load */ +} plugin_data; + + +/* Options */ +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"basedir", 'b', "The basedir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"datadir", 'd', "The datadir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-dir", 'p', "The plugin dir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-ini", 'i', "Read plugin information from configuration file " + "specified instead of from /.ini.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-defaults", 'n', "Do not read values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"print-defaults", 'P', "Show default values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', + "More verbose output; you can use this multiple times to get even more " + "verbose output.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +/* Methods */ +static int process_options(int argc, char *argv[], char *operation); +static int check_access(); +static int find_tool(const char *tool_name, char *tool_path); +static int find_plugin(char *tp_path); +static int build_bootstrap_file(char *operation, char *bootstrap); +static int dump_bootstrap_file(char *bootstrap_file); +static int bootstrap_server(char *server_path, char *bootstrap_file); + + +int main(int argc,char *argv[]) +{ + int error= 0; + char tp_path[FN_REFLEN]; + char server_path[FN_REFLEN]; + char operation[16]; + + MY_INIT(argv[0]); + plugin_data.name= 0; // initialize name + + /* + The following operations comprise the method for enabling or disabling + a plugin. We begin by processing the command options then check the + directories specified for --datadir, --basedir, --plugin-dir, and + --plugin-ini (if specified). If the directories are Ok, we then look + for the mysqld executable and the plugin soname. Finally, we build a + bootstrap command file for use in bootstraping the server. + + If any step fails, the method issues an error message and the tool exits. + + 1) Parse, execute, and verify command options. + 2) Check access to directories. + 3) Look for mysqld executable. + 4) Look for the plugin. + 5) Build a bootstrap file with commands to enable or disable plugin. + + */ + if ((error= process_options(argc, argv, operation)) || + (error= check_access()) || + (error= find_tool("mysqld" FN_EXEEXT, server_path)) || + (error= find_plugin(tp_path)) || + (error= build_bootstrap_file(operation, bootstrap))) + goto exit; + + /* Dump the bootstrap file if --verbose specified. */ + if (opt_verbose && ((error= dump_bootstrap_file(bootstrap)))) + goto exit; + + /* Start the server in bootstrap mode and execute bootstrap commands */ + error= bootstrap_server(server_path, bootstrap); + +exit: + /* Remove file */ + my_delete(bootstrap, MYF(0)); + if (opt_verbose && error == 0) + { + printf("# Operation succeeded.\n"); + } + + my_end(my_end_arg); + exit(error ? 1 : 0); + return 0; /* No compiler warnings */ +} + + +/** + Get a temporary file name. + + @param[out] filename The file name of the temporary file + @param[in] ext An extension for the file (optional) + + @retval int error = 1, success = 0 +*/ + +static int make_tempfile(char *filename, const char *ext) +{ + int fd= 0; + + if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY, + MYF(MY_WME))) < 0) + { + fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n", + fd); + return 1; + } + my_close(fd, MYF(0)); + return 0; +} + + +/** + Get the value of an option from a string read from my_print_defaults output. + + @param[in] line The line (string) read from the file + @param[in] item The option to search for (e.g. --datadir) + + @returns NULL if not found, string containing value if found +*/ + +static char *get_value(char *line, const char *item) +{ + char *destination= 0; + int item_len= (int)strlen(item); + int line_len = (int)strlen(line); + + if ((strncasecmp(line, item, item_len) == 0)) + { + int start= 0; + char *s= 0; + + s = line + item_len + 1; + destination= my_strndup(s, line_len - start, MYF(MY_FAE)); + destination[line_len - item_len - 2]= 0; + } + return destination; +} + + +/** + Run a command in a shell. + + This function will attempt to execute the command specified by using the + popen() method to open a shell and execute the command passed and store the + output in a result file. If the --verbose option was specified, it will open + the result file and print the contents to stdout. + + @param[in] cmd The command to execute. + @param[in] mode The mode for popen() (e.g. "r", "w", "rw") + + @return int error code or 0 for success. +*/ + +static int run_command(char* cmd, const char *mode) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, mode))) + return -1; + + if (opt_verbose) + { + while (fgets(buf, sizeof(buf), res_file)) + { + fprintf(stdout, "%s", buf); + } + } + error= pclose(res_file); + return error; +} + + +/** + Get the default values from the my.cnf file. + + This method gets the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + + These values are used if the user has not specified a value. + + @retval int error = 1, success = 0 +*/ + +static int get_default_values() +{ + char tool_path[FN_REFLEN]; + char defaults_cmd[FN_REFLEN]; + char defaults_file[FN_REFLEN]; + char line[FN_REFLEN]; + int error= 0; + int ret= 0; + FILE *file= 0; + + if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) + goto exit; + else + { + if ((error= make_tempfile(defaults_file, "txt"))) + goto exit; + snprintf(defaults_cmd, sizeof(defaults_cmd), + "%s mysqld > %s", tool_path, defaults_file); + + /* Execute the command */ + if (opt_verbose > 1) + { + printf("# Command: %s\n", defaults_cmd); + } + error= run_command(defaults_cmd, "r"); + if (error) + { + fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n", + ret); + goto exit; + } + /* Now open the file and read the defaults we want. */ + file= fopen(defaults_file, "r"); + while (fgets(line, FN_REFLEN, file) != NULL) + { + char *value= 0; + + if ((opt_datadir == 0) && ((value= get_value(line, "--datadir")))) + { + opt_datadir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_basedir == 0) && ((value= get_value(line, "--basedir")))) + { + opt_basedir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")))) + { + opt_plugin_dir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini")))) + { + opt_plugin_ini= my_strdup(value, MYF(MY_FAE)); + } + } + } +exit: + if (file) + { + fclose(file); + /* Remove file */ + my_delete(defaults_file, MYF(0)); + } + return error; +} + + +/** + Print usage. +*/ + +static void usage(void) +{ + PRINT_VERSION; + puts("Copyright (c) 2011, Oracle and/or its affiliates. " + "All rights reserved.\n"); + puts("Enable or disable plugins."); + printf("\nUsage: %s [options] ENABLE|DISABLE\n\nOptions:\n", + my_progname); + my_print_help(my_long_options); + puts("\n"); +} + + +/** + Print the default values as read from the my.cnf file. + + This method displays the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + +*/ + +static void print_default_values(void) +{ + printf("%s would have been started with the following arguments:\n", + my_progname); + get_default_values(); + if (opt_datadir) + { + printf("--datadir=%s ", opt_datadir); + } + if (opt_basedir) + { + printf("--basedir=%s ", opt_basedir); + } + if (opt_plugin_dir) + { + printf("--plugin_dir=%s ", opt_plugin_dir); + } + if (opt_plugin_ini) + { + printf("--plugin_ini=%s ", opt_plugin_ini); + } + printf("\n"); +} + + +/** + Process the arguments and identify an option and store its value. + + @param[in] optid The single character shortcut for the argument. + @param[in] my_option Structure of legal options. + @param[in] argument The argument value to process. +*/ + +static my_bool +get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch(optid) { + case 'n': + opt_no_defaults++; + break; + case 'P': + opt_print_defaults++; + print_default_values(); + break; + case 'v': + opt_verbose++; + break; + case 'V': + PRINT_VERSION; + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + case 'd': + opt_datadir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'b': + opt_basedir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'p': + opt_plugin_dir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'i': + opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); + break; + } + return 0; +} + + +/** + Check to see if a file exists. + + @param[in] filename File to locate. + + @retval int file not found = 1, file found = 0 +*/ + +static int file_exists(char * filename) +{ + struct stat buf; + int i = stat (filename, &buf); + /* File found */ + if (i == 0) + { + return 1; + } + return 0; +} + + +/** + Search a specific path and sub directory for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[in] subdir The sub directory to search. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_dir(const char * base_path, const char *tool_name, + const char *subdir, char *tool_path) +{ + char new_path[FN_REFLEN]; + + strcpy(new_path, base_path); + strcat(new_path, subdir); + fn_format(new_path, new_path, "", tool_name, MY_UNPACK_FILENAME); + if (file_exists(new_path)) + { + strcpy(tool_path, new_path); + return 1; + } + return 0; +} + + +/** + Search known common paths and sub directories for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_paths(const char *base_path, const char *tool_name, + char *tool_path) +{ + int i= 0; + + static const char *paths[]= { + "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/", + "/mysql/", "/sql/", + }; + for (i = 0 ; i < (int)array_elements(paths); i++) + { + if (search_dir(base_path, tool_name, paths[i], tool_path)) + { + return 1; + } + } + return 0; +} + + +/** + Read a plugin data element + + This method takes as input a line from the plugin.ini file and splits it + into the st_plugin structure. + + @retval int error = 1, success = 0 +*/ + +static int read_plugin_data(char *line) +{ + const char delimiters[]= " ,"; + char *token, *cp; + int i= 0; + int error= 0; + + cp= my_strdup(line, MYF(MY_FAE)); + token= strtok (cp, delimiters); + if (token != NULL) + { + /* read name */ + plugin_data.name= my_strdup(token, MYF(MY_WME)); + /* read so_name */ + token = strtok(NULL, delimiters); + if (token == NULL) + { + return 1; + } + plugin_data.so_name= my_strdup(token, MYF(MY_WME)); + if (plugin_data.so_name == NULL) + { + error= 1; + goto exit; + } + /* Add proper file extension for soname */ + strcat((char *)plugin_data.so_name, FN_SOEXT); + /* read symbols */ + while (token != NULL) + { + token= strtok (NULL, delimiters); + if ((token != NULL) && (token[0] != '\n')) + { + plugin_data.symbols[i]= my_strdup(token, MYF(MY_WME)); + i++; + } + else + { + plugin_data.symbols[i]= NULL; + } + } + } + +exit: + if (error) + { + fprintf(stderr, "ERROR: Format incorrect for plugin config file.\n"); + } + + return error; +} + + +/** + Read the plugin ini file. + + This function attempts to read the plugin config file from the plugin_dir + path. If the file is not found, an error is generated. + + @retval int error = 1, success = 0 +*/ + +static int load_plugin_data(char *plugin_name) +{ + FILE *file_ptr; + char path[FN_REFLEN]; + char line[1024]; + int i= 0; + + if (opt_plugin_ini == 0) + { + fn_format(path, plugin_name, opt_plugin_dir, "", MYF(0)); + opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); + } + if (!file_exists(opt_plugin_ini)) + { + goto error; + } + + file_ptr= fopen(opt_plugin_ini, "r"); + if (file_ptr == NULL) + { + goto error; + } + i = 0; + while (1) + { + char *res; + res= fgets(line, sizeof(line), file_ptr); + if (res == NULL) + { + break; + } + if (line[0] == '#') // skip comment lines + { + continue; + } + if (read_plugin_data(line)) + { + fclose(file_ptr); + goto error; + } + } + fclose(file_ptr); + return 0; + +error: + fprintf(stderr, "ERROR: Cannot read plugin config file %s.\n", + plugin_name); + return 1; +} + + +/** + Check the options for validity. + + This function checks the arguments for validity issuing the appropriate + error message if arguments are missing or invalid. On success, @operation + is set to either "ENABLE" or "DISABLE". + + @param[in] argc The number of arguments. + @param[in] argv The arguments. + @param[out] operation The operation chosen (enable|disable) + + @retval int error = 1, success = 0 +*/ + +static int check_options(int argc, char **argv, char *operation) +{ + int i= 0; // loop counter + int num_found= 0; // number of options found (shortcut loop) + char config_file[FN_REFLEN]; // configuration file name + char plugin_name[FN_REFLEN]; // plugin name + + /* Form prefix strings for the options. */ + const char *basedir_prefix = "--basedir="; + int basedir_len= strlen(basedir_prefix); + const char *datadir_prefix = "--datadir="; + int datadir_len= strlen(datadir_prefix); + const char *plugin_dir_prefix = "--plugin_dir="; + int plugin_dir_len= strlen(plugin_dir_prefix); + + strcpy(plugin_name, ""); + for (i = 0; i < argc && num_found < 5; i++) + { + + if (!argv[i]) + { + continue; + } + if ((strcasecmp(argv[i], "ENABLE") == 0) || + (strcasecmp(argv[i], "DISABLE") == 0)) + { + strcpy(operation, argv[i]); + num_found++; + } + else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) && + !opt_basedir) + { + opt_basedir= my_strndup(argv[i]+basedir_len, + strlen(argv[i])-basedir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) && + !opt_datadir) + { + opt_datadir= my_strndup(argv[i]+datadir_len, + strlen(argv[i])-datadir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) && + !opt_plugin_dir) + { + opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len, + strlen(argv[i])-plugin_dir_len, MYF(MY_FAE)); + num_found++; + } + /* read the plugin config file and check for match against argument */ + else + { + strcpy(plugin_name, argv[i]); + strcpy(config_file, argv[i]); + strcat(config_file, ".ini"); + } + } + + if (!opt_basedir) + { + fprintf(stderr, "ERROR: Missing --basedir option.\n"); + return 1; + } + + if (!opt_datadir) + { + fprintf(stderr, "ERROR: Missing --datadir option.\n"); + return 1; + } + + if (!opt_plugin_dir) + { + fprintf(stderr, "ERROR: Missing --plugin_dir option.\n"); + return 1; + } + /* If a plugin was specified, read the config file. */ + else if (strlen(plugin_name) > 0) + { + if (load_plugin_data(config_file)) + { + return 1; + } + if (strcasecmp(plugin_data.name, plugin_name) != 0) + { + fprintf(stderr, "ERROR: plugin name requested does not match config " + "file data.\n"); + return 1; + } + } + else + { + fprintf(stderr, "ERROR: No plugin specified.\n"); + return 1; + } + + if ((strlen(operation) == 0)) + { + fprintf(stderr, "ERROR: missing operation. Please specify either " + "' ENABLE' or ' DISABLE'.\n"); + return 1; + } + + return 0; +} + + +/** + Parse, execute, and verify command options. + + This method handles all of the option processing including the optional + features for displaying data (--print-defaults, --help ,etc.) that do not + result in an attempt to ENABLE or DISABLE of a plugin. + + @param[in] arc Count of arguments + @param[in] argv Array of arguments + @param[out] operation Operation (ENABLE or DISABLE) + + @retval int error = 1, success = 0, exit program = -1 +*/ + +static int process_options(int argc, char *argv[], char *operation) +{ + int error= 0; + int i= 0; + + /* Parse and execute command-line options */ + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) + goto exit; + + /* If the print defaults option used, exit. */ + if (opt_print_defaults) + { + error= -1; + goto exit; + } + + /* + If the user did not specify the option to skip loading defaults from a + config file and the required options are not present or there was an error + generated when the defaults were read from the file, exit. + */ + if (!opt_no_defaults && ((error= get_default_values()))) + { + error= -1; + goto exit; + } + + /* + Check to ensure required options are present and validate the operation. + Note: this method also validates the plugin specified by attempting to + read a configuration file named .ini from the --plugin-dir + or --plugin-ini location if the --plugin-ini option presented. + */ + strcpy(operation, ""); + if ((error = check_options(argc, argv, operation))) + { + goto exit; + } + + /* Add a trailing directory separator if not present */ + i= (int)strlength(opt_basedir); + if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) + { + strcat(opt_basedir, FN_DIRSEP); + } + + if (opt_verbose) + { + printf("# basedir = %s\n", opt_basedir); + printf("# plugin_dir = %s\n", opt_plugin_dir); + printf("# datadir = %s\n", opt_datadir); + printf("# plugin_ini = %s\n", opt_plugin_ini); + } + +exit: + return error; +} + + +/** + Check access + + This method checks to ensure all of the directories (opt_basedir, + opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by + the user. + + @retval int error = 1, success = 0 +*/ + +static int check_access() +{ + int error= 0; + + if ((error= my_access(opt_basedir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n", + opt_basedir); + goto exit; + } + if ((error= my_access(opt_plugin_dir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n", + opt_plugin_dir); + goto exit; + } + if ((error= my_access(opt_datadir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n", + opt_datadir); + goto exit; + } + if ((error= my_access(opt_plugin_ini, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", + opt_plugin_ini); + goto exit; + } + +exit: + return error; +} + + +/** + Locate the tool and form tool path. + + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int find_tool(const char *tool_name, char *tool_path) +{ + int i= 0; + + const char *paths[]= { + opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", + }; + for (i= 0; i < (int)array_elements(paths); i++) + { + if (paths[i] && (search_paths(paths[i], tool_name, tool_path))) + goto found; + } + fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name); + return 1; +found: + if (opt_verbose) + printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path); + return 0; +} + + +/** + Find the plugin library. + + This function attempts to use the @c plugin_dir option passed on the + command line to locate the plugin. + + @param[out] tp_path The actual path to plugin with FN_SOEXT applied. + + @retval int error = 1, success = 0 +*/ + +static int find_plugin(char *tp_path) +{ + /* Check for existance of plugin */ + fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0)); + if (!file_exists(tp_path)) + { + fprintf(stderr, "ERROR: The plugin library is missing or in a different" + " location.\n"); + return 1; + } + else if (opt_verbose) + { + printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path); + } + return 0; +} + + +/** + Build the boostrap file. + + Create a new file and populate it with SQL commands to ENABLE or DISABLE + the plugin via INSERT and DELETE operations on the mysql.plugin table. + + param[in] operation The type of operation (ENABLE or DISABLE) + param[out] bootstrap A FILE* pointer + + @retval int error = 1, success = 0 +*/ + +static int build_bootstrap_file(char *operation, char *bootstrap) +{ + int error= 0; + FILE *file= 0; + + /* + Perform plugin operation : ENABLE or DISABLE + + The following creates a temporary bootstrap file and populates it with + the appropriate SQL commands for the operation. For ENABLE, INSERT + statements are created. For DISABLE, DELETE statements are created. The + values for these statements are derived from the plugin_data read from the + .ini configuration file. Once the file is built, a call to + mysqld is made in read only, bootstrap modes to read the SQL statements + and execute them. + */ + if ((error= make_tempfile(bootstrap, "sql"))) + { + /* Fail if we cannot create a temporary file for the bootstrap commands. */ + fprintf(stderr, "ERROR: Cannot create bootstrap file.\n"); + goto exit; + } + if ((file= fopen(bootstrap, "w+")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n"); + error= 1; + goto exit; + } + if (strcasecmp(operation, "enable") == 0) + { + int i= 0; + fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES "); + for (i= 0; i < (int)array_elements(plugin_data.symbols); i++) + { + /* stop when we read the end of the symbol list - marked with NULL */ + if (plugin_data.symbols[i] == NULL) + { + break; + } + if (i > 0) + { + fprintf(file, ", "); + } + fprintf(file, "('%s','%s')", + plugin_data.symbols[i], plugin_data.so_name); + } + fprintf(file, ";\n"); + if (opt_verbose) + { + printf("# Enabling %s...\n", plugin_data.name); + } + } + else + { + fprintf(file, + "DELETE FROM mysql.plugin WHERE name = '%s';", plugin_data.name); + if (opt_verbose) + { + printf("# Disabling %s...\n", plugin_data.name); + } + } + +exit: + fclose(file); + return error; +} + + +/** + Dump bootstrap file. + + Read the contents of the bootstrap file and print it out. + + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int dump_bootstrap_file(char *bootstrap_file) +{ + char *ret= 0; + int error= 0; + char query_str[512]; + FILE *file= 0; + + if ((file= fopen(bootstrap_file, "r")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n"); + error= 1; + goto exit; + } + ret= fgets(query_str, 512, file); + if (ret == 0) + { + fprintf(stderr, "ERROR: Cannot read bootstrap file.\n"); + error= 1; + goto exit; + } + printf("# Query: %s", query_str); + +exit: + if (file) + { + fclose(file); + } + return error; +} + + +/** + Bootstrap the server + + Create a command line sequence to launch mysqld in bootstrap mode. This + will allow mysqld to launch a minimal server instance to read and + execute SQL commands from a file piped in (the boostrap file). We use + the --no-defaults option to skip reading values from the config file. + + The bootstrap mode skips loading of plugins and many other subsystems. + This allows the mysql_plugin tool to insert the correct rows into the + mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once + the server is launched in normal mode, the plugin will be loaded + (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the + (sometimes) complicated LOAD PLUGIN commands. + + @param[in] server_path Path to server executable + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int bootstrap_server(char *server_path, char *bootstrap_file) +{ + char bootstrap_cmd[FN_REFLEN]; + int error= 0; + int ret= 0; + + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), + "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" + " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); + + /* Execute the command */ + if (opt_verbose > 1) + { + printf("# Command: %s\n", bootstrap_cmd); + } + error= run_command(bootstrap_cmd, "r"); + if (error) + fprintf(stderr, + "ERROR: Unexpected result from bootstrap. Error code: %d.\n", + ret); + + return error; +} diff --git a/include/my_global.h b/include/my_global.h index f465d031b62..924c83cd951 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -603,6 +603,8 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '\\' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/\\" /* Valid directory separators */ +#define FN_EXEEXT ".exe" +#define FN_SOEXT ".dll" #define FN_ROOTDIR "\\" #define FN_DEVCHAR ':' #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ @@ -611,6 +613,8 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '/' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/" /* Valid directory separators */ +#define FN_EXEEXT "" +#define FN_SOEXT ".so" #define FN_ROOTDIR "/" #endif diff --git a/mysql-test/include/daemon_example.ini b/mysql-test/include/daemon_example.ini new file mode 100644 index 00000000000..2fbfca203ea --- /dev/null +++ b/mysql-test/include/daemon_example.ini @@ -0,0 +1,8 @@ +# +# Plugin initialization file. Format using comma-separated values: +# name, libname, symbol, [symbol, ] +# Note: trailing comma is required. +# +# File is used by mysql_plugin.test for testing missing library error. +# +daemon_example, libdaemon_example, daemon_example, diff --git a/mysql-test/include/daemon_example_bad_format.ini b/mysql-test/include/daemon_example_bad_format.ini new file mode 100644 index 00000000000..a08e50632c9 --- /dev/null +++ b/mysql-test/include/daemon_example_bad_format.ini @@ -0,0 +1,8 @@ +# +# Plugin initialization file. Format using comma-separated values: +# name, libname, symbol, [symbol, ] +# Note: trailing comma is required. +# +# File is used by mysql_plugin.test for testing bad library name. +# +daemon_BADNAME, libdaemon_example, daemon_example, diff --git a/mysql-test/include/plugin.defs b/mysql-test/include/plugin.defs index e07c603c8e5..6fbe4f68328 100644 --- a/mysql-test/include/plugin.defs +++ b/mysql-test/include/plugin.defs @@ -39,3 +39,4 @@ ha_archive storage/archive ARCHIVE_PLUGIN ha_blackhole storage/blackhole BLACKHOLE_PLUGIN ha_federated storage/federated FEDERATED_PLUGIN mypluglib plugin/fulltext SIMPLE_PARSER +libdaemon_example plugin/daemon_example DAEMONEXAMPLE diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 82d17a21f89..ec0ca74b1d1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -168,6 +168,7 @@ my $opt_suites; our $opt_verbose= 0; # Verbose output, enable with --verbose our $exe_mysql; +our $exe_mysql_plugin; our $exe_mysqladmin; our $exe_mysqltest; our $exe_libtool; @@ -1950,6 +1951,7 @@ sub executable_setup () { # Look for the client binaries $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + $exe_mysql_plugin= mtr_exe_exists("$path_client_bindir/mysql_plugin"); $exe_mysql_embedded= mtr_exe_maybe_exists("$basedir/libmysqld/examples/mysql_embedded"); @@ -2357,6 +2359,7 @@ sub environment_setup { $ENV{'MYSQLADMIN'}= native_path($exe_mysqladmin); $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); $ENV{'EXE_MYSQL'}= $exe_mysql; + $ENV{'MYSQL_PLUGIN'}= $exe_mysql_plugin; $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded; # ---------------------------------------------------- diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result new file mode 100644 index 00000000000..4aebf532db1 --- /dev/null +++ b/mysql-test/r/mysql_plugin.result @@ -0,0 +1,97 @@ +# +# Ensure the plugin isn't loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +# +# Enable the plugin... +# +# +# Ensure the plugin is now loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +daemon_example libdaemon_example.so +# +# Disable the plugin... +# +# +# Ensure the plugin isn't loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +# +# Attempt to load non-existant plugin +# +ERROR: Cannot read plugin config file NOT_THERE_AT_ALL.ini. +# +# Attempt to use non-existant plugin.ini file +# +ERROR: Cannot read plugin config file daemon_example.ini. +# +# Attempt to omit the plugin +# +ERROR: No plugin specified. +# +# Attempt to omit DISABLE|ENABLE +# +ERROR: missing operation. Please specify either ' ENABLE' or ' DISABLE'. +# +# Attempt to use bad paths - datadir +# +ERROR: Cannot access datadir at '/data_not_there/'. +# +# Attempt to use bad paths - basedir +# +ERROR: Cannot access basedir at '/basedir_not_there/'. +# +# Attempt to use bad paths - plugin_dir +# +ERROR: Cannot read plugin config file daemon_example.ini. +# +# Missing library +# +ERROR: The plugin library is missing or in a different location. +# +# Bad format for config file +# +ERROR: plugin name requested does not match config file data. +# +# Missing base_dir option +# +ERROR: Missing --basedir option. +# +# Missing data_dir option +# +ERROR: Missing --datadir option. +# +# Missing plugin_dir option +# +ERROR: Missing --plugin_dir option. +# +# Show the help. +# +mysql_plugin Ver 1.0.0 Distrib XX.XX.XX +Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + +Enable or disable plugins. + +Usage: mysql_plugin [options] ENABLE|DISABLE + +Options: + -?, --help Display this help and exit. + -b, --basedir=name The basedir for the server. + -d, --datadir=name The datadir for the server. + -p, --plugin-dir=name + The plugin dir for the server. + -i, --plugin-ini=name + Read plugin information from configuration file specified + instead of from /.ini. + -n, --no-defaults Do not read values from configuration file. + -P, --print-defaults + Show default values from configuration file. + -v, --verbose More verbose output; you can use this multiple times to + get even more verbose output. + -V, --version Output version information and exit. + + diff --git a/mysql-test/t/mysql_plugin-master.opt b/mysql-test/t/mysql_plugin-master.opt new file mode 100644 index 00000000000..061ca907902 --- /dev/null +++ b/mysql-test/t/mysql_plugin-master.opt @@ -0,0 +1 @@ +--plugin-dir=$DAEMONEXAMPLE_DIR diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test new file mode 100644 index 00000000000..3257adfeb61 --- /dev/null +++ b/mysql-test/t/mysql_plugin.test @@ -0,0 +1,205 @@ +# +# Test mysql_plugin tool +# + +# +# Test currently does not run on Windows because in Windows build trees, +# mysqld.exe is not placed in the ./sql folder - it is placed either +# in ./sql/Debug or ./sql/release. If this behaviour is changed, this test +# can run on Windows. +# +--source include/not_windows.inc + +# Add the datadir, basedir, plugin_dir to the bootstrap command +let $MYSQLD_DATADIR= `select @@datadir`; +let $MYSQLD_BASEDIR= `select @@basedir`; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; + +--echo # +--echo # Ensure the plugin isn't loaded. +--echo # +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +--echo # +--echo # Enable the plugin... +--echo # +let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +# +# Enable the plugin +# +--exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example + +# +# Ensure enabling an enabled plugin doesn't fail +--exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo # +--echo # Ensure the plugin is now loaded. +--echo # +--replace_regex /\.dll/.so/ +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +--echo # +--echo # Disable the plugin... +--echo # +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +# +# Disable the plugin +# +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo # +--echo # Ensure the plugin isn't loaded. +--echo # +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +# +# Stop the server for error conditions +# +let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +--echo # +--echo # Attempt to load non-existant plugin +--echo # +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE NOT_THERE_AT_ALL 2>&1 + +--echo # +--echo # Attempt to use non-existant plugin.ini file +--echo # +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1 + +--echo # +--echo # Attempt to omit the plugin +--echo # +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE 2>&1 + +--echo # +--echo # Attempt to omit DISABLE|ENABLE +--echo # +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - datadir +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - basedir +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$DAEMONEXAMPLE_DIR; +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - plugin_dir +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=/plugin_not_there/; +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing library +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$MYSQL_TEST_DIR/include/; +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Bad format for config file +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini; +--error 1,2,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing base_dir option +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$DAEMONEXAMPLE_DIR; +--error 1,2,139,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing data_dir option +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; +--error 1,2,139,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing plugin_dir option +--echo # +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql; +--error 1,2,139,256 +--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Show the help. +--echo # +replace_result $MYSQL_PLUGIN mysql_plugin; +--replace_regex /Distrib [0-9.]+/Distrib XX.XX.XX/ +--exec $MYSQL_PLUGIN --help + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +# +# Cleanup +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file + diff --git a/plugin/daemon_example/CMakeLists.txt b/plugin/daemon_example/CMakeLists.txt index 60aa00687ba..1623c3025d7 100644 --- a/plugin/daemon_example/CMakeLists.txt +++ b/plugin/daemon_example/CMakeLists.txt @@ -15,3 +15,5 @@ MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc MODULE_ONLY MODULE_OUTPUT_NAME "libdaemon_example") + +INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR}) diff --git a/plugin/daemon_example/daemon_example.ini b/plugin/daemon_example/daemon_example.ini new file mode 100644 index 00000000000..8d84456b635 --- /dev/null +++ b/plugin/daemon_example/daemon_example.ini @@ -0,0 +1,6 @@ +# +# Plugin initialization file. Format using comma-separated values: +# name, libname, symbol, [symbol, ] +# Note: trailing comma is required. +# +daemon_example, libdaemon_example, daemon_example, From 33a36da65a0e5403903bc85d1c85729b54c0968e Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 10:24:14 -0400 Subject: [PATCH 004/143] WL#5710 : Enable and disable plugins (mysql_plugin) This patch changes the plugin configuration file format to make it easier to add new plugins and remove complexity. It also adds more information when plugin configuration file reads fail. --- client/mysql_plugin.c | 135 +++++++++-------------- mysql-test/r/mysql_plugin.result | 8 +- plugin/daemon_example/daemon_example.ini | 11 +- 3 files changed, 64 insertions(+), 90 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index ca3da0086e4..d904d2dabcd 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -41,9 +41,9 @@ static char bootstrap[FN_REFLEN]; /* plugin struct */ struct st_plugin { - const char *name; /* plugin name */ - const char *so_name; /* plugin so (library) name */ - const char *symbols[16]; /* symbols to load */ + const char *name; /* plugin name */ + const char *so_name; /* plugin so (library) name */ + const char *components[16]; /* components to load */ } plugin_data; @@ -491,124 +491,95 @@ static int search_paths(const char *base_path, const char *tool_name, } -/** - Read a plugin data element - - This method takes as input a line from the plugin.ini file and splits it - into the st_plugin structure. - - @retval int error = 1, success = 0 -*/ - -static int read_plugin_data(char *line) -{ - const char delimiters[]= " ,"; - char *token, *cp; - int i= 0; - int error= 0; - - cp= my_strdup(line, MYF(MY_FAE)); - token= strtok (cp, delimiters); - if (token != NULL) - { - /* read name */ - plugin_data.name= my_strdup(token, MYF(MY_WME)); - /* read so_name */ - token = strtok(NULL, delimiters); - if (token == NULL) - { - return 1; - } - plugin_data.so_name= my_strdup(token, MYF(MY_WME)); - if (plugin_data.so_name == NULL) - { - error= 1; - goto exit; - } - /* Add proper file extension for soname */ - strcat((char *)plugin_data.so_name, FN_SOEXT); - /* read symbols */ - while (token != NULL) - { - token= strtok (NULL, delimiters); - if ((token != NULL) && (token[0] != '\n')) - { - plugin_data.symbols[i]= my_strdup(token, MYF(MY_WME)); - i++; - } - else - { - plugin_data.symbols[i]= NULL; - } - } - } - -exit: - if (error) - { - fprintf(stderr, "ERROR: Format incorrect for plugin config file.\n"); - } - - return error; -} - - /** Read the plugin ini file. This function attempts to read the plugin config file from the plugin_dir - path. If the file is not found, an error is generated. + path saving the data in the the st_plugin structure. If the file is not + found or the file cannot be read, an error is generated. @retval int error = 1, success = 0 */ -static int load_plugin_data(char *plugin_name) +static int load_plugin_data(char *plugin_name, char *config_file) { FILE *file_ptr; char path[FN_REFLEN]; char line[1024]; - int i= 0; + char *reason= 0; + char *res; + int i= -1; if (opt_plugin_ini == 0) { - fn_format(path, plugin_name, opt_plugin_dir, "", MYF(0)); + fn_format(path, config_file, opt_plugin_dir, "", MYF(0)); opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); } if (!file_exists(opt_plugin_ini)) { + reason= "File does not exist."; goto error; } file_ptr= fopen(opt_plugin_ini, "r"); if (file_ptr == NULL) { + reason= "Cannot open file."; goto error; } - i = 0; - while (1) + + /* save name */ + plugin_data.name= my_strdup(plugin_name, MYF(MY_WME)); + + /* Read plugin components */ + while (i < 16) { - char *res; res= fgets(line, sizeof(line), file_ptr); + /* strip /n */ + if (line[strlen(line)-1] == '\n') + { + line[strlen(line)-1]= '\0'; + } if (res == NULL) { break; } - if (line[0] == '#') // skip comment lines + if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines { continue; } - if (read_plugin_data(line)) + if (i == -1) // if first pass, read this line as so_name { - fclose(file_ptr); - goto error; + /* save so_name */ + plugin_data.so_name= my_strdup(line, MYF(MY_WME)); + if (plugin_data.so_name == NULL) + { + reason= "Cannot read library name."; + goto error; + } + /* Add proper file extension for soname */ + strcat((char *)plugin_data.so_name, FN_SOEXT); + i++; + } + else + { + if (strlen(line) > 0) + { + plugin_data.components[i]= my_strdup(line, MYF(MY_WME)); + i++; + } + else + { + plugin_data.components[i]= NULL; + } } } fclose(file_ptr); return 0; error: - fprintf(stderr, "ERROR: Cannot read plugin config file %s.\n", - plugin_name); + fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n", + plugin_name, reason); return 1; } @@ -706,7 +677,7 @@ static int check_options(int argc, char **argv, char *operation) /* If a plugin was specified, read the config file. */ else if (strlen(plugin_name) > 0) { - if (load_plugin_data(config_file)) + if (load_plugin_data(plugin_name, config_file)) { return 1; } @@ -954,10 +925,10 @@ static int build_bootstrap_file(char *operation, char *bootstrap) { int i= 0; fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES "); - for (i= 0; i < (int)array_elements(plugin_data.symbols); i++) + for (i= 0; i < (int)array_elements(plugin_data.components); i++) { /* stop when we read the end of the symbol list - marked with NULL */ - if (plugin_data.symbols[i] == NULL) + if (plugin_data.components[i] == NULL) { break; } @@ -966,7 +937,7 @@ static int build_bootstrap_file(char *operation, char *bootstrap) fprintf(file, ", "); } fprintf(file, "('%s','%s')", - plugin_data.symbols[i], plugin_data.so_name); + plugin_data.components[i], plugin_data.so_name); } fprintf(file, ";\n"); if (opt_verbose) diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result index 4aebf532db1..f64d215978a 100644 --- a/mysql-test/r/mysql_plugin.result +++ b/mysql-test/r/mysql_plugin.result @@ -23,11 +23,11 @@ name dl # # Attempt to load non-existant plugin # -ERROR: Cannot read plugin config file NOT_THERE_AT_ALL.ini. +ERROR: Cannot read plugin config file NOT_THERE_AT_ALL. File does not exist. # # Attempt to use non-existant plugin.ini file # -ERROR: Cannot read plugin config file daemon_example.ini. +ERROR: Cannot read plugin config file daemon_example. File does not exist. # # Attempt to omit the plugin # @@ -47,7 +47,7 @@ ERROR: Cannot access basedir at '/basedir_not_there/'. # # Attempt to use bad paths - plugin_dir # -ERROR: Cannot read plugin config file daemon_example.ini. +ERROR: Cannot read plugin config file daemon_example. File does not exist. # # Missing library # @@ -55,7 +55,7 @@ ERROR: The plugin library is missing or in a different location. # # Bad format for config file # -ERROR: plugin name requested does not match config file data. +ERROR: The plugin library is missing or in a different location. # # Missing base_dir option # diff --git a/plugin/daemon_example/daemon_example.ini b/plugin/daemon_example/daemon_example.ini index 8d84456b635..7c6d4d1456e 100644 --- a/plugin/daemon_example/daemon_example.ini +++ b/plugin/daemon_example/daemon_example.ini @@ -1,6 +1,9 @@ # -# Plugin initialization file. Format using comma-separated values: -# name, libname, symbol, [symbol, ] -# Note: trailing comma is required. +# Plugin configuration file. Place the following on a separate line: # -daemon_example, libdaemon_example, daemon_example, +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin +# +libdaemon_example +daemon_example From 9e112497785d5e7ce627c825aa39e2b17a5aa73e Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 10:27:15 -0400 Subject: [PATCH 005/143] BUG#12707948 : mysql_plugin cannot run on Windows Patch fixes an issue with reading basedir on Windows. It fixes how the code interprets opt_basedir on Windows by adding the correct path separators and quotes for paths with spaces. BUG#12664302 : mysql_plugin cannot recognize the plugin config file Patch fixes an issue with reading a plugin config file. It adds more information to the error messages to ensure the user is using the options correctly. Also deals with paths with spacs on Windows. --- client/mysql_plugin.c | 136 +++++++++++++++--- mysql-test/include/daemon_example.ini | 8 -- .../include/daemon_example_bad_format.ini | 10 +- .../include/daemon_example_bad_soname.ini | 9 ++ mysql-test/r/mysql_plugin.result | 2 +- mysql-test/t/mysql_plugin.test | 2 +- 6 files changed, 136 insertions(+), 31 deletions(-) delete mode 100644 mysql-test/include/daemon_example.ini create mode 100644 mysql-test/include/daemon_example_bad_soname.ini diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index d904d2dabcd..2da9c2d6f16 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -228,6 +228,69 @@ static int run_command(char* cmd, const char *mode) } +#ifdef __WIN__ +/** + Check to see if there are spaces in a path. + + @param[in] path The Windows path to examine. + + @retval int spaces found = 1, no spaces = 0 +*/ +static int has_spaces(const char *path) +{ + if (strchr(path, ' ') != NULL) + return 1; + return 0; +} + + +/** + Convert a Unix path to a Windows path. + + @param[in] path The Windows path to examine. + + @returns string containing path with / changed to \\ +*/ +static char *convert_path(const char *argument) +{ + /* Convert / to \\ to make Windows paths */ + char *winfilename= my_strdup(argument, MYF(MY_FAE)); + char *pos, *end; + int length= strlen(argument); + + for (pos= winfilename, end= pos+length ; pos < end ; pos++) + { + if (*pos == '/') + { + *pos= '\\'; + } + } + return winfilename; +} + + +/** + Add quotes if the path has spaces in it. + + @param[in] path The Windows path to examine. + + @returns string containing excaped quotes if spaces found in path +*/ +static char *add_quotes(const char *path) +{ + char windows_cmd_friendly[FN_REFLEN]; + + if (has_spaces(path)) + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "\"%s\"", path); + else + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "%s", path); + return my_strdup(windows_cmd_friendly, MYF(MY_FAE)); +} +#endif + + /** Get the default values from the my.cnf file. @@ -259,11 +322,26 @@ static int get_default_values() { if ((error= make_tempfile(defaults_file, "txt"))) goto exit; + +#ifdef __WIN__ + { + char *format_str= 0; + + if (has_spaces(tool_path) || has_spaces(defaults_file)) + format_str = "\"%s mysqld > %s\""; + else + format_str = "%s mysqld > %s"; + + snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, + add_quotes(tool_path), add_quotes(defaults_file)); + } +#else snprintf(defaults_cmd, sizeof(defaults_cmd), "%s mysqld > %s", tool_path, defaults_file); +#endif /* Execute the command */ - if (opt_verbose > 1) + if (opt_verbose) { printf("# Command: %s\n", defaults_cmd); } @@ -517,14 +595,14 @@ static int load_plugin_data(char *plugin_name, char *config_file) } if (!file_exists(opt_plugin_ini)) { - reason= "File does not exist."; + reason= (char *)"File does not exist."; goto error; } file_ptr= fopen(opt_plugin_ini, "r"); if (file_ptr == NULL) { - reason= "Cannot open file."; + reason= (char *)"Cannot open file."; goto error; } @@ -542,6 +620,12 @@ static int load_plugin_data(char *plugin_name, char *config_file) } if (res == NULL) { + if (i < 1) + { + reason= (char *)"Bad format in plugin configuration file."; + fclose(file_ptr); + goto error; + } break; } if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines @@ -552,11 +636,6 @@ static int load_plugin_data(char *plugin_name, char *config_file) { /* save so_name */ plugin_data.so_name= my_strdup(line, MYF(MY_WME)); - if (plugin_data.so_name == NULL) - { - reason= "Cannot read library name."; - goto error; - } /* Add proper file extension for soname */ strcat((char *)plugin_data.so_name, FN_SOEXT); i++; @@ -574,6 +653,7 @@ static int load_plugin_data(char *plugin_name, char *config_file) } } } + fclose(file_ptr); return 0; @@ -735,6 +815,19 @@ static int process_options(int argc, char *argv[], char *operation) goto exit; } + /* Add a trailing directory separator if not present */ + if (opt_basedir) + { + i= (int)strlength(opt_basedir); + if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) +#ifdef __WIN__ + if (opt_basedir[i-1] != '/') + strcat(opt_basedir, "//"); +#else + strcat(opt_basedir, FN_DIRSEP); +#endif + } + /* If the user did not specify the option to skip loading defaults from a config file and the required options are not present or there was an error @@ -758,13 +851,6 @@ static int process_options(int argc, char *argv[], char *operation) goto exit; } - /* Add a trailing directory separator if not present */ - i= (int)strlength(opt_basedir); - if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) - { - strcat(opt_basedir, FN_DIRSEP); - } - if (opt_verbose) { printf("# basedir = %s\n", opt_basedir); @@ -1029,12 +1115,30 @@ static int bootstrap_server(char *server_path, char *bootstrap_file) int error= 0; int ret= 0; +#ifdef __WIN__ + char *format_str= 0; + char *verbose_str= ""; + + if (opt_verbose) + strcat(verbose_str, "--console"); + if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || + has_spaces(bootstrap_file)) + format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; + else + format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s"; + + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str, + add_quotes(convert_path(server_path)), verbose_str, + add_quotes(opt_datadir), add_quotes(opt_basedir), + add_quotes(bootstrap_file)); +#else snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); +#endif /* Execute the command */ - if (opt_verbose > 1) + if (opt_verbose) { printf("# Command: %s\n", bootstrap_cmd); } diff --git a/mysql-test/include/daemon_example.ini b/mysql-test/include/daemon_example.ini deleted file mode 100644 index 2fbfca203ea..00000000000 --- a/mysql-test/include/daemon_example.ini +++ /dev/null @@ -1,8 +0,0 @@ -# -# Plugin initialization file. Format using comma-separated values: -# name, libname, symbol, [symbol, ] -# Note: trailing comma is required. -# -# File is used by mysql_plugin.test for testing missing library error. -# -daemon_example, libdaemon_example, daemon_example, diff --git a/mysql-test/include/daemon_example_bad_format.ini b/mysql-test/include/daemon_example_bad_format.ini index a08e50632c9..8f880ef0ba0 100644 --- a/mysql-test/include/daemon_example_bad_format.ini +++ b/mysql-test/include/daemon_example_bad_format.ini @@ -1,8 +1,8 @@ # -# Plugin initialization file. Format using comma-separated values: -# name, libname, symbol, [symbol, ] -# Note: trailing comma is required. +# Plugin configuration file. Place the following on a separate line: # -# File is used by mysql_plugin.test for testing bad library name. +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin # -daemon_BADNAME, libdaemon_example, daemon_example, +libdaemon_example diff --git a/mysql-test/include/daemon_example_bad_soname.ini b/mysql-test/include/daemon_example_bad_soname.ini new file mode 100644 index 00000000000..5f42b5a6214 --- /dev/null +++ b/mysql-test/include/daemon_example_bad_soname.ini @@ -0,0 +1,9 @@ +# +# Plugin configuration file. Place the following on a separate line: +# +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin +# +libdaemon_BADNAME +daemon_BADNAME diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result index f64d215978a..90924b6f4e3 100644 --- a/mysql-test/r/mysql_plugin.result +++ b/mysql-test/r/mysql_plugin.result @@ -55,7 +55,7 @@ ERROR: The plugin library is missing or in a different location. # # Bad format for config file # -ERROR: The plugin library is missing or in a different location. +ERROR: Cannot read plugin config file daemon_example. Bad format in plugin configuration file. # # Missing base_dir option # diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 3257adfeb61..c2c0a403ab3 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -149,7 +149,7 @@ let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir= --echo # --echo # Missing library --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$MYSQL_TEST_DIR/include/; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini; --error 1,2,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 From e73ee41c6cb0fa13c6225c06d072f1d484085827 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 10:35:03 -0400 Subject: [PATCH 006/143] WL#5710 : Enable and disable plugins (mysql_plugin) This patch adds additional QA tests and enhances the mysql_plugin test to include more test cases. --- mysql-test/r/mysql_plugin.result | 3 +- mysql-test/t/mysql_plugin.test | 69 ++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result index 90924b6f4e3..1a39c86ab9a 100644 --- a/mysql-test/r/mysql_plugin.result +++ b/mysql-test/r/mysql_plugin.result @@ -71,7 +71,7 @@ ERROR: Missing --plugin_dir option. # # Show the help. # -mysql_plugin Ver 1.0.0 Distrib XX.XX.XX +mysql_plugin Ver V.V.VV Distrib XX.XX.XX Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. Enable or disable plugins. @@ -95,3 +95,4 @@ Options: -V, --version Output version information and exit. +mysql_plugin Ver V.V.VV Distrib XX.XX.XX diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index c2c0a403ab3..b90619774df 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -2,18 +2,34 @@ # Test mysql_plugin tool # -# -# Test currently does not run on Windows because in Windows build trees, -# mysqld.exe is not placed in the ./sql folder - it is placed either -# in ./sql/Debug or ./sql/release. If this behaviour is changed, this test -# can run on Windows. -# ---source include/not_windows.inc +--source include/not_embedded.inc # Add the datadir, basedir, plugin_dir to the bootstrap command let $MYSQLD_DATADIR= `select @@datadir`; -let $MYSQLD_BASEDIR= `select @@basedir`; -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQL_BASEDIR= `select @@basedir`; + +# The mysql_plugin tool expects all executables in "basedir", so they will be copied to it. +# It also expects a directory structure like in the installed mysql version, so errmsg.sys +# will be copied to "basedir/share". The directories differ between Windows and Unix. +--disable_abort_on_error +if(`SELECT CONVERT(@@version_compile_os USING latin1) + IN ('Win32','Win64','Windows')`) +{ + let $MYSQLD_BASEDIR= $MYSQL_BASEDIR/sql/Debug; + --copy_file $MYSQL_BASEDIR/extra/Debug/my_print_defaults.exe $MYSQLD_BASEDIR/my_print_defaults.exe + --mkdir $MYSQLD_BASEDIR/share + --copy_file $MYSQL_BASEDIR/sql/share/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys + --copy_file $MYSQL_BASEDIR/plugin/daemon_example/daemon_example.ini $DAEMONEXAMPLE_DIR/daemon_example.ini +} +if (`SELECT CONVERT(@@version_compile_os USING latin1) + NOT IN ('Win32','Win64','Windows')`) +{ + let $MYSQLD_BASEDIR= $MYSQL_BASEDIR/sql; + --copy_file $MYSQL_BASEDIR/extra/my_print_defaults $MYSQLD_BASEDIR/my_print_defaults + --copy_file $MYSQL_BASEDIR/sql/share/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys +} + +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; --echo # --echo # Ensure the plugin isn't loaded. @@ -110,7 +126,7 @@ EOF --echo # --echo # Attempt to use non-existant plugin.ini file --echo # ---error 1,2,256 +--error 1,2,7,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1 --echo # @@ -128,7 +144,7 @@ EOF --echo # --echo # Attempt to use bad paths - datadir --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; --error 1,2,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 @@ -142,21 +158,21 @@ let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir= --echo # --echo # Attempt to use bad paths - plugin_dir --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=/plugin_not_there/; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=/plugin_not_there/; --error 1,2,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing library --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini; --error 1,2,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 --echo # --echo # Bad format for config file --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini; --error 1,2,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 @@ -170,14 +186,14 @@ let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-d --echo # --echo # Missing data_dir option --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; --error 1,2,139,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing plugin_dir option --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql; +let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR; --error 1,2,139,256 --exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 @@ -185,9 +201,13 @@ let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir= --echo # Show the help. --echo # replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Distrib [0-9.]+/Distrib XX.XX.XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ --exec $MYSQL_PLUGIN --help +replace_result $MYSQL_PLUGIN mysql_plugin; +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--exec $MYSQL_PLUGIN --version + # # Restart the server # @@ -203,3 +223,18 @@ EOF --error 0,1 --remove_file $expect_file +if(`SELECT CONVERT(@@version_compile_os USING latin1) + IN ('Win32','Win64','Windows')`) +{ + --remove_file $DAEMONEXAMPLE_DIR/daemon_example.ini + --remove_file $MYSQLD_BASEDIR/my_print_defaults.exe + --remove_file $MYSQLD_BASEDIR/share/errmsg.sys + --rmdir $MYSQLD_BASEDIR/share +} +if(`SELECT CONVERT(@@version_compile_os USING latin1) + NOT IN ('Win32','Win64','Windows')`) +{ + --remove_file $MYSQLD_BASEDIR/my_print_defaults + --remove_file $MYSQLD_BASEDIR/share/errmsg.sys +} +--enable_abort_on_error From 5ae1ff7001044c3ef222c3c781aab636bf618d35 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 15:55:03 -0400 Subject: [PATCH 007/143] WL#5710 : Enable and disable plugins This patch fixes line endings in the mysql_plugin.c file. --- client/mysql_plugin.c | 2304 ++++++++++++++++++++--------------------- 1 file changed, 1152 insertions(+), 1152 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 2da9c2d6f16..58ca69ed778 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1,1152 +1,1152 @@ -/* 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 -*/ - -#include -#include -#include -#include -#include -#include -#include - - -#define SHOW_VERSION "1.0.0" -#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \ - my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \ - } while(0) - -/* Global variables. */ -static uint my_end_arg= 0; -static uint opt_verbose=0; -static uint opt_no_defaults= 0; -static uint opt_print_defaults= 0; -static char *opt_datadir=0, *opt_basedir=0, - *opt_plugin_dir=0, *opt_plugin_ini=0; -static char bootstrap[FN_REFLEN]; - - -/* plugin struct */ -struct st_plugin -{ - const char *name; /* plugin name */ - const char *so_name; /* plugin so (library) name */ - const char *components[16]; /* components to load */ -} plugin_data; - - -/* Options */ -static struct my_option my_long_options[] = -{ - {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, - {"basedir", 'b', "The basedir for the server.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"datadir", 'd', "The datadir for the server.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin-dir", 'p', "The plugin dir for the server.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin-ini", 'i', "Read plugin information from configuration file " - "specified instead of from /.ini.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"no-defaults", 'n', "Do not read values from configuration file.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"print-defaults", 'P', "Show default values from configuration file.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', - "More verbose output; you can use this multiple times to get even more " - "verbose output.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, - NO_ARG, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - - -/* Methods */ -static int process_options(int argc, char *argv[], char *operation); -static int check_access(); -static int find_tool(const char *tool_name, char *tool_path); -static int find_plugin(char *tp_path); -static int build_bootstrap_file(char *operation, char *bootstrap); -static int dump_bootstrap_file(char *bootstrap_file); -static int bootstrap_server(char *server_path, char *bootstrap_file); - - -int main(int argc,char *argv[]) -{ - int error= 0; - char tp_path[FN_REFLEN]; - char server_path[FN_REFLEN]; - char operation[16]; - - MY_INIT(argv[0]); - plugin_data.name= 0; // initialize name - - /* - The following operations comprise the method for enabling or disabling - a plugin. We begin by processing the command options then check the - directories specified for --datadir, --basedir, --plugin-dir, and - --plugin-ini (if specified). If the directories are Ok, we then look - for the mysqld executable and the plugin soname. Finally, we build a - bootstrap command file for use in bootstraping the server. - - If any step fails, the method issues an error message and the tool exits. - - 1) Parse, execute, and verify command options. - 2) Check access to directories. - 3) Look for mysqld executable. - 4) Look for the plugin. - 5) Build a bootstrap file with commands to enable or disable plugin. - - */ - if ((error= process_options(argc, argv, operation)) || - (error= check_access()) || - (error= find_tool("mysqld" FN_EXEEXT, server_path)) || - (error= find_plugin(tp_path)) || - (error= build_bootstrap_file(operation, bootstrap))) - goto exit; - - /* Dump the bootstrap file if --verbose specified. */ - if (opt_verbose && ((error= dump_bootstrap_file(bootstrap)))) - goto exit; - - /* Start the server in bootstrap mode and execute bootstrap commands */ - error= bootstrap_server(server_path, bootstrap); - -exit: - /* Remove file */ - my_delete(bootstrap, MYF(0)); - if (opt_verbose && error == 0) - { - printf("# Operation succeeded.\n"); - } - - my_end(my_end_arg); - exit(error ? 1 : 0); - return 0; /* No compiler warnings */ -} - - -/** - Get a temporary file name. - - @param[out] filename The file name of the temporary file - @param[in] ext An extension for the file (optional) - - @retval int error = 1, success = 0 -*/ - -static int make_tempfile(char *filename, const char *ext) -{ - int fd= 0; - - if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY, - MYF(MY_WME))) < 0) - { - fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n", - fd); - return 1; - } - my_close(fd, MYF(0)); - return 0; -} - - -/** - Get the value of an option from a string read from my_print_defaults output. - - @param[in] line The line (string) read from the file - @param[in] item The option to search for (e.g. --datadir) - - @returns NULL if not found, string containing value if found -*/ - -static char *get_value(char *line, const char *item) -{ - char *destination= 0; - int item_len= (int)strlen(item); - int line_len = (int)strlen(line); - - if ((strncasecmp(line, item, item_len) == 0)) - { - int start= 0; - char *s= 0; - - s = line + item_len + 1; - destination= my_strndup(s, line_len - start, MYF(MY_FAE)); - destination[line_len - item_len - 2]= 0; - } - return destination; -} - - -/** - Run a command in a shell. - - This function will attempt to execute the command specified by using the - popen() method to open a shell and execute the command passed and store the - output in a result file. If the --verbose option was specified, it will open - the result file and print the contents to stdout. - - @param[in] cmd The command to execute. - @param[in] mode The mode for popen() (e.g. "r", "w", "rw") - - @return int error code or 0 for success. -*/ - -static int run_command(char* cmd, const char *mode) -{ - char buf[512]= {0}; - FILE *res_file; - int error; - - if (!(res_file= popen(cmd, mode))) - return -1; - - if (opt_verbose) - { - while (fgets(buf, sizeof(buf), res_file)) - { - fprintf(stdout, "%s", buf); - } - } - error= pclose(res_file); - return error; -} - - -#ifdef __WIN__ -/** - Check to see if there are spaces in a path. - - @param[in] path The Windows path to examine. - - @retval int spaces found = 1, no spaces = 0 -*/ -static int has_spaces(const char *path) -{ - if (strchr(path, ' ') != NULL) - return 1; - return 0; -} - - -/** - Convert a Unix path to a Windows path. - - @param[in] path The Windows path to examine. - - @returns string containing path with / changed to \\ -*/ -static char *convert_path(const char *argument) -{ - /* Convert / to \\ to make Windows paths */ - char *winfilename= my_strdup(argument, MYF(MY_FAE)); - char *pos, *end; - int length= strlen(argument); - - for (pos= winfilename, end= pos+length ; pos < end ; pos++) - { - if (*pos == '/') - { - *pos= '\\'; - } - } - return winfilename; -} - - -/** - Add quotes if the path has spaces in it. - - @param[in] path The Windows path to examine. - - @returns string containing excaped quotes if spaces found in path -*/ -static char *add_quotes(const char *path) -{ - char windows_cmd_friendly[FN_REFLEN]; - - if (has_spaces(path)) - snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), - "\"%s\"", path); - else - snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), - "%s", path); - return my_strdup(windows_cmd_friendly, MYF(MY_FAE)); -} -#endif - - -/** - Get the default values from the my.cnf file. - - This method gets the default values for the following parameters: - - --datadir - --basedir - --plugin-dir - --plugin-ini - - These values are used if the user has not specified a value. - - @retval int error = 1, success = 0 -*/ - -static int get_default_values() -{ - char tool_path[FN_REFLEN]; - char defaults_cmd[FN_REFLEN]; - char defaults_file[FN_REFLEN]; - char line[FN_REFLEN]; - int error= 0; - int ret= 0; - FILE *file= 0; - - if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) - goto exit; - else - { - if ((error= make_tempfile(defaults_file, "txt"))) - goto exit; - -#ifdef __WIN__ - { - char *format_str= 0; - - if (has_spaces(tool_path) || has_spaces(defaults_file)) - format_str = "\"%s mysqld > %s\""; - else - format_str = "%s mysqld > %s"; - - snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, - add_quotes(tool_path), add_quotes(defaults_file)); - } -#else - snprintf(defaults_cmd, sizeof(defaults_cmd), - "%s mysqld > %s", tool_path, defaults_file); -#endif - - /* Execute the command */ - if (opt_verbose) - { - printf("# Command: %s\n", defaults_cmd); - } - error= run_command(defaults_cmd, "r"); - if (error) - { - fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n", - ret); - goto exit; - } - /* Now open the file and read the defaults we want. */ - file= fopen(defaults_file, "r"); - while (fgets(line, FN_REFLEN, file) != NULL) - { - char *value= 0; - - if ((opt_datadir == 0) && ((value= get_value(line, "--datadir")))) - { - opt_datadir= my_strdup(value, MYF(MY_FAE)); - } - if ((opt_basedir == 0) && ((value= get_value(line, "--basedir")))) - { - opt_basedir= my_strdup(value, MYF(MY_FAE)); - } - if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")))) - { - opt_plugin_dir= my_strdup(value, MYF(MY_FAE)); - } - if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini")))) - { - opt_plugin_ini= my_strdup(value, MYF(MY_FAE)); - } - } - } -exit: - if (file) - { - fclose(file); - /* Remove file */ - my_delete(defaults_file, MYF(0)); - } - return error; -} - - -/** - Print usage. -*/ - -static void usage(void) -{ - PRINT_VERSION; - puts("Copyright (c) 2011, Oracle and/or its affiliates. " - "All rights reserved.\n"); - puts("Enable or disable plugins."); - printf("\nUsage: %s [options] ENABLE|DISABLE\n\nOptions:\n", - my_progname); - my_print_help(my_long_options); - puts("\n"); -} - - -/** - Print the default values as read from the my.cnf file. - - This method displays the default values for the following parameters: - - --datadir - --basedir - --plugin-dir - --plugin-ini - -*/ - -static void print_default_values(void) -{ - printf("%s would have been started with the following arguments:\n", - my_progname); - get_default_values(); - if (opt_datadir) - { - printf("--datadir=%s ", opt_datadir); - } - if (opt_basedir) - { - printf("--basedir=%s ", opt_basedir); - } - if (opt_plugin_dir) - { - printf("--plugin_dir=%s ", opt_plugin_dir); - } - if (opt_plugin_ini) - { - printf("--plugin_ini=%s ", opt_plugin_ini); - } - printf("\n"); -} - - -/** - Process the arguments and identify an option and store its value. - - @param[in] optid The single character shortcut for the argument. - @param[in] my_option Structure of legal options. - @param[in] argument The argument value to process. -*/ - -static my_bool -get_one_option(int optid, - const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch(optid) { - case 'n': - opt_no_defaults++; - break; - case 'P': - opt_print_defaults++; - print_default_values(); - break; - case 'v': - opt_verbose++; - break; - case 'V': - PRINT_VERSION; - exit(0); - break; - case '?': - case 'I': /* Info */ - usage(); - exit(0); - case 'd': - opt_datadir= my_strdup(argument, MYF(MY_FAE)); - break; - case 'b': - opt_basedir= my_strdup(argument, MYF(MY_FAE)); - break; - case 'p': - opt_plugin_dir= my_strdup(argument, MYF(MY_FAE)); - break; - case 'i': - opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); - break; - } - return 0; -} - - -/** - Check to see if a file exists. - - @param[in] filename File to locate. - - @retval int file not found = 1, file found = 0 -*/ - -static int file_exists(char * filename) -{ - struct stat buf; - int i = stat (filename, &buf); - /* File found */ - if (i == 0) - { - return 1; - } - return 0; -} - - -/** - Search a specific path and sub directory for a file name. - - @param[in] base_path Original path to use. - @param[in] tool_name Name of the tool to locate. - @param[in] subdir The sub directory to search. - @param[out] tool_path If tool found, return complete path. - - @retval int error = 1, success = 0 -*/ - -static int search_dir(const char * base_path, const char *tool_name, - const char *subdir, char *tool_path) -{ - char new_path[FN_REFLEN]; - - strcpy(new_path, base_path); - strcat(new_path, subdir); - fn_format(new_path, new_path, "", tool_name, MY_UNPACK_FILENAME); - if (file_exists(new_path)) - { - strcpy(tool_path, new_path); - return 1; - } - return 0; -} - - -/** - Search known common paths and sub directories for a file name. - - @param[in] base_path Original path to use. - @param[in] tool_name Name of the tool to locate. - @param[out] tool_path If tool found, return complete path. - - @retval int error = 1, success = 0 -*/ - -static int search_paths(const char *base_path, const char *tool_name, - char *tool_path) -{ - int i= 0; - - static const char *paths[]= { - "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/", - "/mysql/", "/sql/", - }; - for (i = 0 ; i < (int)array_elements(paths); i++) - { - if (search_dir(base_path, tool_name, paths[i], tool_path)) - { - return 1; - } - } - return 0; -} - - -/** - Read the plugin ini file. - - This function attempts to read the plugin config file from the plugin_dir - path saving the data in the the st_plugin structure. If the file is not - found or the file cannot be read, an error is generated. - - @retval int error = 1, success = 0 -*/ - -static int load_plugin_data(char *plugin_name, char *config_file) -{ - FILE *file_ptr; - char path[FN_REFLEN]; - char line[1024]; - char *reason= 0; - char *res; - int i= -1; - - if (opt_plugin_ini == 0) - { - fn_format(path, config_file, opt_plugin_dir, "", MYF(0)); - opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); - } - if (!file_exists(opt_plugin_ini)) - { - reason= (char *)"File does not exist."; - goto error; - } - - file_ptr= fopen(opt_plugin_ini, "r"); - if (file_ptr == NULL) - { - reason= (char *)"Cannot open file."; - goto error; - } - - /* save name */ - plugin_data.name= my_strdup(plugin_name, MYF(MY_WME)); - - /* Read plugin components */ - while (i < 16) - { - res= fgets(line, sizeof(line), file_ptr); - /* strip /n */ - if (line[strlen(line)-1] == '\n') - { - line[strlen(line)-1]= '\0'; - } - if (res == NULL) - { - if (i < 1) - { - reason= (char *)"Bad format in plugin configuration file."; - fclose(file_ptr); - goto error; - } - break; - } - if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines - { - continue; - } - if (i == -1) // if first pass, read this line as so_name - { - /* save so_name */ - plugin_data.so_name= my_strdup(line, MYF(MY_WME)); - /* Add proper file extension for soname */ - strcat((char *)plugin_data.so_name, FN_SOEXT); - i++; - } - else - { - if (strlen(line) > 0) - { - plugin_data.components[i]= my_strdup(line, MYF(MY_WME)); - i++; - } - else - { - plugin_data.components[i]= NULL; - } - } - } - - fclose(file_ptr); - return 0; - -error: - fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n", - plugin_name, reason); - return 1; -} - - -/** - Check the options for validity. - - This function checks the arguments for validity issuing the appropriate - error message if arguments are missing or invalid. On success, @operation - is set to either "ENABLE" or "DISABLE". - - @param[in] argc The number of arguments. - @param[in] argv The arguments. - @param[out] operation The operation chosen (enable|disable) - - @retval int error = 1, success = 0 -*/ - -static int check_options(int argc, char **argv, char *operation) -{ - int i= 0; // loop counter - int num_found= 0; // number of options found (shortcut loop) - char config_file[FN_REFLEN]; // configuration file name - char plugin_name[FN_REFLEN]; // plugin name - - /* Form prefix strings for the options. */ - const char *basedir_prefix = "--basedir="; - int basedir_len= strlen(basedir_prefix); - const char *datadir_prefix = "--datadir="; - int datadir_len= strlen(datadir_prefix); - const char *plugin_dir_prefix = "--plugin_dir="; - int plugin_dir_len= strlen(plugin_dir_prefix); - - strcpy(plugin_name, ""); - for (i = 0; i < argc && num_found < 5; i++) - { - - if (!argv[i]) - { - continue; - } - if ((strcasecmp(argv[i], "ENABLE") == 0) || - (strcasecmp(argv[i], "DISABLE") == 0)) - { - strcpy(operation, argv[i]); - num_found++; - } - else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) && - !opt_basedir) - { - opt_basedir= my_strndup(argv[i]+basedir_len, - strlen(argv[i])-basedir_len, MYF(MY_FAE)); - num_found++; - } - else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) && - !opt_datadir) - { - opt_datadir= my_strndup(argv[i]+datadir_len, - strlen(argv[i])-datadir_len, MYF(MY_FAE)); - num_found++; - } - else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) && - !opt_plugin_dir) - { - opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len, - strlen(argv[i])-plugin_dir_len, MYF(MY_FAE)); - num_found++; - } - /* read the plugin config file and check for match against argument */ - else - { - strcpy(plugin_name, argv[i]); - strcpy(config_file, argv[i]); - strcat(config_file, ".ini"); - } - } - - if (!opt_basedir) - { - fprintf(stderr, "ERROR: Missing --basedir option.\n"); - return 1; - } - - if (!opt_datadir) - { - fprintf(stderr, "ERROR: Missing --datadir option.\n"); - return 1; - } - - if (!opt_plugin_dir) - { - fprintf(stderr, "ERROR: Missing --plugin_dir option.\n"); - return 1; - } - /* If a plugin was specified, read the config file. */ - else if (strlen(plugin_name) > 0) - { - if (load_plugin_data(plugin_name, config_file)) - { - return 1; - } - if (strcasecmp(plugin_data.name, plugin_name) != 0) - { - fprintf(stderr, "ERROR: plugin name requested does not match config " - "file data.\n"); - return 1; - } - } - else - { - fprintf(stderr, "ERROR: No plugin specified.\n"); - return 1; - } - - if ((strlen(operation) == 0)) - { - fprintf(stderr, "ERROR: missing operation. Please specify either " - "' ENABLE' or ' DISABLE'.\n"); - return 1; - } - - return 0; -} - - -/** - Parse, execute, and verify command options. - - This method handles all of the option processing including the optional - features for displaying data (--print-defaults, --help ,etc.) that do not - result in an attempt to ENABLE or DISABLE of a plugin. - - @param[in] arc Count of arguments - @param[in] argv Array of arguments - @param[out] operation Operation (ENABLE or DISABLE) - - @retval int error = 1, success = 0, exit program = -1 -*/ - -static int process_options(int argc, char *argv[], char *operation) -{ - int error= 0; - int i= 0; - - /* Parse and execute command-line options */ - if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) - goto exit; - - /* If the print defaults option used, exit. */ - if (opt_print_defaults) - { - error= -1; - goto exit; - } - - /* Add a trailing directory separator if not present */ - if (opt_basedir) - { - i= (int)strlength(opt_basedir); - if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) -#ifdef __WIN__ - if (opt_basedir[i-1] != '/') - strcat(opt_basedir, "//"); -#else - strcat(opt_basedir, FN_DIRSEP); -#endif - } - - /* - If the user did not specify the option to skip loading defaults from a - config file and the required options are not present or there was an error - generated when the defaults were read from the file, exit. - */ - if (!opt_no_defaults && ((error= get_default_values()))) - { - error= -1; - goto exit; - } - - /* - Check to ensure required options are present and validate the operation. - Note: this method also validates the plugin specified by attempting to - read a configuration file named .ini from the --plugin-dir - or --plugin-ini location if the --plugin-ini option presented. - */ - strcpy(operation, ""); - if ((error = check_options(argc, argv, operation))) - { - goto exit; - } - - if (opt_verbose) - { - printf("# basedir = %s\n", opt_basedir); - printf("# plugin_dir = %s\n", opt_plugin_dir); - printf("# datadir = %s\n", opt_datadir); - printf("# plugin_ini = %s\n", opt_plugin_ini); - } - -exit: - return error; -} - - -/** - Check access - - This method checks to ensure all of the directories (opt_basedir, - opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by - the user. - - @retval int error = 1, success = 0 -*/ - -static int check_access() -{ - int error= 0; - - if ((error= my_access(opt_basedir, F_OK))) - { - fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n", - opt_basedir); - goto exit; - } - if ((error= my_access(opt_plugin_dir, F_OK))) - { - fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n", - opt_plugin_dir); - goto exit; - } - if ((error= my_access(opt_datadir, F_OK))) - { - fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n", - opt_datadir); - goto exit; - } - if ((error= my_access(opt_plugin_ini, F_OK))) - { - fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", - opt_plugin_ini); - goto exit; - } - -exit: - return error; -} - - -/** - Locate the tool and form tool path. - - @param[in] tool_name Name of the tool to locate. - @param[out] tool_path If tool found, return complete path. - - @retval int error = 1, success = 0 -*/ - -static int find_tool(const char *tool_name, char *tool_path) -{ - int i= 0; - - const char *paths[]= { - opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", - }; - for (i= 0; i < (int)array_elements(paths); i++) - { - if (paths[i] && (search_paths(paths[i], tool_name, tool_path))) - goto found; - } - fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name); - return 1; -found: - if (opt_verbose) - printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path); - return 0; -} - - -/** - Find the plugin library. - - This function attempts to use the @c plugin_dir option passed on the - command line to locate the plugin. - - @param[out] tp_path The actual path to plugin with FN_SOEXT applied. - - @retval int error = 1, success = 0 -*/ - -static int find_plugin(char *tp_path) -{ - /* Check for existance of plugin */ - fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0)); - if (!file_exists(tp_path)) - { - fprintf(stderr, "ERROR: The plugin library is missing or in a different" - " location.\n"); - return 1; - } - else if (opt_verbose) - { - printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path); - } - return 0; -} - - -/** - Build the boostrap file. - - Create a new file and populate it with SQL commands to ENABLE or DISABLE - the plugin via INSERT and DELETE operations on the mysql.plugin table. - - param[in] operation The type of operation (ENABLE or DISABLE) - param[out] bootstrap A FILE* pointer - - @retval int error = 1, success = 0 -*/ - -static int build_bootstrap_file(char *operation, char *bootstrap) -{ - int error= 0; - FILE *file= 0; - - /* - Perform plugin operation : ENABLE or DISABLE - - The following creates a temporary bootstrap file and populates it with - the appropriate SQL commands for the operation. For ENABLE, INSERT - statements are created. For DISABLE, DELETE statements are created. The - values for these statements are derived from the plugin_data read from the - .ini configuration file. Once the file is built, a call to - mysqld is made in read only, bootstrap modes to read the SQL statements - and execute them. - */ - if ((error= make_tempfile(bootstrap, "sql"))) - { - /* Fail if we cannot create a temporary file for the bootstrap commands. */ - fprintf(stderr, "ERROR: Cannot create bootstrap file.\n"); - goto exit; - } - if ((file= fopen(bootstrap, "w+")) == NULL) - { - fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n"); - error= 1; - goto exit; - } - if (strcasecmp(operation, "enable") == 0) - { - int i= 0; - fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES "); - for (i= 0; i < (int)array_elements(plugin_data.components); i++) - { - /* stop when we read the end of the symbol list - marked with NULL */ - if (plugin_data.components[i] == NULL) - { - break; - } - if (i > 0) - { - fprintf(file, ", "); - } - fprintf(file, "('%s','%s')", - plugin_data.components[i], plugin_data.so_name); - } - fprintf(file, ";\n"); - if (opt_verbose) - { - printf("# Enabling %s...\n", plugin_data.name); - } - } - else - { - fprintf(file, - "DELETE FROM mysql.plugin WHERE name = '%s';", plugin_data.name); - if (opt_verbose) - { - printf("# Disabling %s...\n", plugin_data.name); - } - } - -exit: - fclose(file); - return error; -} - - -/** - Dump bootstrap file. - - Read the contents of the bootstrap file and print it out. - - @param[in] bootstrap_file Name of bootstrap file to read - - @retval int error = 1, success = 0 -*/ - -static int dump_bootstrap_file(char *bootstrap_file) -{ - char *ret= 0; - int error= 0; - char query_str[512]; - FILE *file= 0; - - if ((file= fopen(bootstrap_file, "r")) == NULL) - { - fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n"); - error= 1; - goto exit; - } - ret= fgets(query_str, 512, file); - if (ret == 0) - { - fprintf(stderr, "ERROR: Cannot read bootstrap file.\n"); - error= 1; - goto exit; - } - printf("# Query: %s", query_str); - -exit: - if (file) - { - fclose(file); - } - return error; -} - - -/** - Bootstrap the server - - Create a command line sequence to launch mysqld in bootstrap mode. This - will allow mysqld to launch a minimal server instance to read and - execute SQL commands from a file piped in (the boostrap file). We use - the --no-defaults option to skip reading values from the config file. - - The bootstrap mode skips loading of plugins and many other subsystems. - This allows the mysql_plugin tool to insert the correct rows into the - mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once - the server is launched in normal mode, the plugin will be loaded - (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the - (sometimes) complicated LOAD PLUGIN commands. - - @param[in] server_path Path to server executable - @param[in] bootstrap_file Name of bootstrap file to read - - @retval int error = 1, success = 0 -*/ - -static int bootstrap_server(char *server_path, char *bootstrap_file) -{ - char bootstrap_cmd[FN_REFLEN]; - int error= 0; - int ret= 0; - -#ifdef __WIN__ - char *format_str= 0; - char *verbose_str= ""; - - if (opt_verbose) - strcat(verbose_str, "--console"); - if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || - has_spaces(bootstrap_file)) - format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; - else - format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s"; - - snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str, - add_quotes(convert_path(server_path)), verbose_str, - add_quotes(opt_datadir), add_quotes(opt_basedir), - add_quotes(bootstrap_file)); -#else - snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), - "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" - " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); -#endif - - /* Execute the command */ - if (opt_verbose) - { - printf("# Command: %s\n", bootstrap_cmd); - } - error= run_command(bootstrap_cmd, "r"); - if (error) - fprintf(stderr, - "ERROR: Unexpected result from bootstrap. Error code: %d.\n", - ret); - - return error; -} +/* 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 +*/ + +#include +#include +#include +#include +#include +#include +#include + + +#define SHOW_VERSION "1.0.0" +#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \ + my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \ + } while(0) + +/* Global variables. */ +static uint my_end_arg= 0; +static uint opt_verbose=0; +static uint opt_no_defaults= 0; +static uint opt_print_defaults= 0; +static char *opt_datadir=0, *opt_basedir=0, + *opt_plugin_dir=0, *opt_plugin_ini=0; +static char bootstrap[FN_REFLEN]; + + +/* plugin struct */ +struct st_plugin +{ + const char *name; /* plugin name */ + const char *so_name; /* plugin so (library) name */ + const char *components[16]; /* components to load */ +} plugin_data; + + +/* Options */ +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"basedir", 'b', "The basedir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"datadir", 'd', "The datadir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-dir", 'p', "The plugin dir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-ini", 'i', "Read plugin information from configuration file " + "specified instead of from /.ini.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-defaults", 'n', "Do not read values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"print-defaults", 'P', "Show default values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', + "More verbose output; you can use this multiple times to get even more " + "verbose output.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +/* Methods */ +static int process_options(int argc, char *argv[], char *operation); +static int check_access(); +static int find_tool(const char *tool_name, char *tool_path); +static int find_plugin(char *tp_path); +static int build_bootstrap_file(char *operation, char *bootstrap); +static int dump_bootstrap_file(char *bootstrap_file); +static int bootstrap_server(char *server_path, char *bootstrap_file); + + +int main(int argc,char *argv[]) +{ + int error= 0; + char tp_path[FN_REFLEN]; + char server_path[FN_REFLEN]; + char operation[16]; + + MY_INIT(argv[0]); + plugin_data.name= 0; // initialize name + + /* + The following operations comprise the method for enabling or disabling + a plugin. We begin by processing the command options then check the + directories specified for --datadir, --basedir, --plugin-dir, and + --plugin-ini (if specified). If the directories are Ok, we then look + for the mysqld executable and the plugin soname. Finally, we build a + bootstrap command file for use in bootstraping the server. + + If any step fails, the method issues an error message and the tool exits. + + 1) Parse, execute, and verify command options. + 2) Check access to directories. + 3) Look for mysqld executable. + 4) Look for the plugin. + 5) Build a bootstrap file with commands to enable or disable plugin. + + */ + if ((error= process_options(argc, argv, operation)) || + (error= check_access()) || + (error= find_tool("mysqld" FN_EXEEXT, server_path)) || + (error= find_plugin(tp_path)) || + (error= build_bootstrap_file(operation, bootstrap))) + goto exit; + + /* Dump the bootstrap file if --verbose specified. */ + if (opt_verbose && ((error= dump_bootstrap_file(bootstrap)))) + goto exit; + + /* Start the server in bootstrap mode and execute bootstrap commands */ + error= bootstrap_server(server_path, bootstrap); + +exit: + /* Remove file */ + my_delete(bootstrap, MYF(0)); + if (opt_verbose && error == 0) + { + printf("# Operation succeeded.\n"); + } + + my_end(my_end_arg); + exit(error ? 1 : 0); + return 0; /* No compiler warnings */ +} + + +/** + Get a temporary file name. + + @param[out] filename The file name of the temporary file + @param[in] ext An extension for the file (optional) + + @retval int error = 1, success = 0 +*/ + +static int make_tempfile(char *filename, const char *ext) +{ + int fd= 0; + + if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY, + MYF(MY_WME))) < 0) + { + fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n", + fd); + return 1; + } + my_close(fd, MYF(0)); + return 0; +} + + +/** + Get the value of an option from a string read from my_print_defaults output. + + @param[in] line The line (string) read from the file + @param[in] item The option to search for (e.g. --datadir) + + @returns NULL if not found, string containing value if found +*/ + +static char *get_value(char *line, const char *item) +{ + char *destination= 0; + int item_len= (int)strlen(item); + int line_len = (int)strlen(line); + + if ((strncasecmp(line, item, item_len) == 0)) + { + int start= 0; + char *s= 0; + + s = line + item_len + 1; + destination= my_strndup(s, line_len - start, MYF(MY_FAE)); + destination[line_len - item_len - 2]= 0; + } + return destination; +} + + +/** + Run a command in a shell. + + This function will attempt to execute the command specified by using the + popen() method to open a shell and execute the command passed and store the + output in a result file. If the --verbose option was specified, it will open + the result file and print the contents to stdout. + + @param[in] cmd The command to execute. + @param[in] mode The mode for popen() (e.g. "r", "w", "rw") + + @return int error code or 0 for success. +*/ + +static int run_command(char* cmd, const char *mode) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, mode))) + return -1; + + if (opt_verbose) + { + while (fgets(buf, sizeof(buf), res_file)) + { + fprintf(stdout, "%s", buf); + } + } + error= pclose(res_file); + return error; +} + + +#ifdef __WIN__ +/** + Check to see if there are spaces in a path. + + @param[in] path The Windows path to examine. + + @retval int spaces found = 1, no spaces = 0 +*/ +static int has_spaces(const char *path) +{ + if (strchr(path, ' ') != NULL) + return 1; + return 0; +} + + +/** + Convert a Unix path to a Windows path. + + @param[in] path The Windows path to examine. + + @returns string containing path with / changed to \\ +*/ +static char *convert_path(const char *argument) +{ + /* Convert / to \\ to make Windows paths */ + char *winfilename= my_strdup(argument, MYF(MY_FAE)); + char *pos, *end; + int length= strlen(argument); + + for (pos= winfilename, end= pos+length ; pos < end ; pos++) + { + if (*pos == '/') + { + *pos= '\\'; + } + } + return winfilename; +} + + +/** + Add quotes if the path has spaces in it. + + @param[in] path The Windows path to examine. + + @returns string containing excaped quotes if spaces found in path +*/ +static char *add_quotes(const char *path) +{ + char windows_cmd_friendly[FN_REFLEN]; + + if (has_spaces(path)) + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "\"%s\"", path); + else + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "%s", path); + return my_strdup(windows_cmd_friendly, MYF(MY_FAE)); +} +#endif + + +/** + Get the default values from the my.cnf file. + + This method gets the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + + These values are used if the user has not specified a value. + + @retval int error = 1, success = 0 +*/ + +static int get_default_values() +{ + char tool_path[FN_REFLEN]; + char defaults_cmd[FN_REFLEN]; + char defaults_file[FN_REFLEN]; + char line[FN_REFLEN]; + int error= 0; + int ret= 0; + FILE *file= 0; + + if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) + goto exit; + else + { + if ((error= make_tempfile(defaults_file, "txt"))) + goto exit; + +#ifdef __WIN__ + { + char *format_str= 0; + + if (has_spaces(tool_path) || has_spaces(defaults_file)) + format_str = "\"%s mysqld > %s\""; + else + format_str = "%s mysqld > %s"; + + snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, + add_quotes(tool_path), add_quotes(defaults_file)); + } +#else + snprintf(defaults_cmd, sizeof(defaults_cmd), + "%s mysqld > %s", tool_path, defaults_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", defaults_cmd); + } + error= run_command(defaults_cmd, "r"); + if (error) + { + fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n", + ret); + goto exit; + } + /* Now open the file and read the defaults we want. */ + file= fopen(defaults_file, "r"); + while (fgets(line, FN_REFLEN, file) != NULL) + { + char *value= 0; + + if ((opt_datadir == 0) && ((value= get_value(line, "--datadir")))) + { + opt_datadir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_basedir == 0) && ((value= get_value(line, "--basedir")))) + { + opt_basedir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")))) + { + opt_plugin_dir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini")))) + { + opt_plugin_ini= my_strdup(value, MYF(MY_FAE)); + } + } + } +exit: + if (file) + { + fclose(file); + /* Remove file */ + my_delete(defaults_file, MYF(0)); + } + return error; +} + + +/** + Print usage. +*/ + +static void usage(void) +{ + PRINT_VERSION; + puts("Copyright (c) 2011, Oracle and/or its affiliates. " + "All rights reserved.\n"); + puts("Enable or disable plugins."); + printf("\nUsage: %s [options] ENABLE|DISABLE\n\nOptions:\n", + my_progname); + my_print_help(my_long_options); + puts("\n"); +} + + +/** + Print the default values as read from the my.cnf file. + + This method displays the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + +*/ + +static void print_default_values(void) +{ + printf("%s would have been started with the following arguments:\n", + my_progname); + get_default_values(); + if (opt_datadir) + { + printf("--datadir=%s ", opt_datadir); + } + if (opt_basedir) + { + printf("--basedir=%s ", opt_basedir); + } + if (opt_plugin_dir) + { + printf("--plugin_dir=%s ", opt_plugin_dir); + } + if (opt_plugin_ini) + { + printf("--plugin_ini=%s ", opt_plugin_ini); + } + printf("\n"); +} + + +/** + Process the arguments and identify an option and store its value. + + @param[in] optid The single character shortcut for the argument. + @param[in] my_option Structure of legal options. + @param[in] argument The argument value to process. +*/ + +static my_bool +get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch(optid) { + case 'n': + opt_no_defaults++; + break; + case 'P': + opt_print_defaults++; + print_default_values(); + break; + case 'v': + opt_verbose++; + break; + case 'V': + PRINT_VERSION; + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + case 'd': + opt_datadir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'b': + opt_basedir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'p': + opt_plugin_dir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'i': + opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); + break; + } + return 0; +} + + +/** + Check to see if a file exists. + + @param[in] filename File to locate. + + @retval int file not found = 1, file found = 0 +*/ + +static int file_exists(char * filename) +{ + struct stat buf; + int i = stat (filename, &buf); + /* File found */ + if (i == 0) + { + return 1; + } + return 0; +} + + +/** + Search a specific path and sub directory for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[in] subdir The sub directory to search. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_dir(const char * base_path, const char *tool_name, + const char *subdir, char *tool_path) +{ + char new_path[FN_REFLEN]; + + strcpy(new_path, base_path); + strcat(new_path, subdir); + fn_format(new_path, new_path, "", tool_name, MY_UNPACK_FILENAME); + if (file_exists(new_path)) + { + strcpy(tool_path, new_path); + return 1; + } + return 0; +} + + +/** + Search known common paths and sub directories for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_paths(const char *base_path, const char *tool_name, + char *tool_path) +{ + int i= 0; + + static const char *paths[]= { + "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/", + "/mysql/", "/sql/", + }; + for (i = 0 ; i < (int)array_elements(paths); i++) + { + if (search_dir(base_path, tool_name, paths[i], tool_path)) + { + return 1; + } + } + return 0; +} + + +/** + Read the plugin ini file. + + This function attempts to read the plugin config file from the plugin_dir + path saving the data in the the st_plugin structure. If the file is not + found or the file cannot be read, an error is generated. + + @retval int error = 1, success = 0 +*/ + +static int load_plugin_data(char *plugin_name, char *config_file) +{ + FILE *file_ptr; + char path[FN_REFLEN]; + char line[1024]; + char *reason= 0; + char *res; + int i= -1; + + if (opt_plugin_ini == 0) + { + fn_format(path, config_file, opt_plugin_dir, "", MYF(0)); + opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); + } + if (!file_exists(opt_plugin_ini)) + { + reason= (char *)"File does not exist."; + goto error; + } + + file_ptr= fopen(opt_plugin_ini, "r"); + if (file_ptr == NULL) + { + reason= (char *)"Cannot open file."; + goto error; + } + + /* save name */ + plugin_data.name= my_strdup(plugin_name, MYF(MY_WME)); + + /* Read plugin components */ + while (i < 16) + { + res= fgets(line, sizeof(line), file_ptr); + /* strip /n */ + if (line[strlen(line)-1] == '\n') + { + line[strlen(line)-1]= '\0'; + } + if (res == NULL) + { + if (i < 1) + { + reason= (char *)"Bad format in plugin configuration file."; + fclose(file_ptr); + goto error; + } + break; + } + if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines + { + continue; + } + if (i == -1) // if first pass, read this line as so_name + { + /* save so_name */ + plugin_data.so_name= my_strdup(line, MYF(MY_WME)); + /* Add proper file extension for soname */ + strcat((char *)plugin_data.so_name, FN_SOEXT); + i++; + } + else + { + if (strlen(line) > 0) + { + plugin_data.components[i]= my_strdup(line, MYF(MY_WME)); + i++; + } + else + { + plugin_data.components[i]= NULL; + } + } + } + + fclose(file_ptr); + return 0; + +error: + fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n", + plugin_name, reason); + return 1; +} + + +/** + Check the options for validity. + + This function checks the arguments for validity issuing the appropriate + error message if arguments are missing or invalid. On success, @operation + is set to either "ENABLE" or "DISABLE". + + @param[in] argc The number of arguments. + @param[in] argv The arguments. + @param[out] operation The operation chosen (enable|disable) + + @retval int error = 1, success = 0 +*/ + +static int check_options(int argc, char **argv, char *operation) +{ + int i= 0; // loop counter + int num_found= 0; // number of options found (shortcut loop) + char config_file[FN_REFLEN]; // configuration file name + char plugin_name[FN_REFLEN]; // plugin name + + /* Form prefix strings for the options. */ + const char *basedir_prefix = "--basedir="; + int basedir_len= strlen(basedir_prefix); + const char *datadir_prefix = "--datadir="; + int datadir_len= strlen(datadir_prefix); + const char *plugin_dir_prefix = "--plugin_dir="; + int plugin_dir_len= strlen(plugin_dir_prefix); + + strcpy(plugin_name, ""); + for (i = 0; i < argc && num_found < 5; i++) + { + + if (!argv[i]) + { + continue; + } + if ((strcasecmp(argv[i], "ENABLE") == 0) || + (strcasecmp(argv[i], "DISABLE") == 0)) + { + strcpy(operation, argv[i]); + num_found++; + } + else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) && + !opt_basedir) + { + opt_basedir= my_strndup(argv[i]+basedir_len, + strlen(argv[i])-basedir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) && + !opt_datadir) + { + opt_datadir= my_strndup(argv[i]+datadir_len, + strlen(argv[i])-datadir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) && + !opt_plugin_dir) + { + opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len, + strlen(argv[i])-plugin_dir_len, MYF(MY_FAE)); + num_found++; + } + /* read the plugin config file and check for match against argument */ + else + { + strcpy(plugin_name, argv[i]); + strcpy(config_file, argv[i]); + strcat(config_file, ".ini"); + } + } + + if (!opt_basedir) + { + fprintf(stderr, "ERROR: Missing --basedir option.\n"); + return 1; + } + + if (!opt_datadir) + { + fprintf(stderr, "ERROR: Missing --datadir option.\n"); + return 1; + } + + if (!opt_plugin_dir) + { + fprintf(stderr, "ERROR: Missing --plugin_dir option.\n"); + return 1; + } + /* If a plugin was specified, read the config file. */ + else if (strlen(plugin_name) > 0) + { + if (load_plugin_data(plugin_name, config_file)) + { + return 1; + } + if (strcasecmp(plugin_data.name, plugin_name) != 0) + { + fprintf(stderr, "ERROR: plugin name requested does not match config " + "file data.\n"); + return 1; + } + } + else + { + fprintf(stderr, "ERROR: No plugin specified.\n"); + return 1; + } + + if ((strlen(operation) == 0)) + { + fprintf(stderr, "ERROR: missing operation. Please specify either " + "' ENABLE' or ' DISABLE'.\n"); + return 1; + } + + return 0; +} + + +/** + Parse, execute, and verify command options. + + This method handles all of the option processing including the optional + features for displaying data (--print-defaults, --help ,etc.) that do not + result in an attempt to ENABLE or DISABLE of a plugin. + + @param[in] arc Count of arguments + @param[in] argv Array of arguments + @param[out] operation Operation (ENABLE or DISABLE) + + @retval int error = 1, success = 0, exit program = -1 +*/ + +static int process_options(int argc, char *argv[], char *operation) +{ + int error= 0; + int i= 0; + + /* Parse and execute command-line options */ + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) + goto exit; + + /* If the print defaults option used, exit. */ + if (opt_print_defaults) + { + error= -1; + goto exit; + } + + /* Add a trailing directory separator if not present */ + if (opt_basedir) + { + i= (int)strlength(opt_basedir); + if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) +#ifdef __WIN__ + if (opt_basedir[i-1] != '/') + strcat(opt_basedir, "//"); +#else + strcat(opt_basedir, FN_DIRSEP); +#endif + } + + /* + If the user did not specify the option to skip loading defaults from a + config file and the required options are not present or there was an error + generated when the defaults were read from the file, exit. + */ + if (!opt_no_defaults && ((error= get_default_values()))) + { + error= -1; + goto exit; + } + + /* + Check to ensure required options are present and validate the operation. + Note: this method also validates the plugin specified by attempting to + read a configuration file named .ini from the --plugin-dir + or --plugin-ini location if the --plugin-ini option presented. + */ + strcpy(operation, ""); + if ((error = check_options(argc, argv, operation))) + { + goto exit; + } + + if (opt_verbose) + { + printf("# basedir = %s\n", opt_basedir); + printf("# plugin_dir = %s\n", opt_plugin_dir); + printf("# datadir = %s\n", opt_datadir); + printf("# plugin_ini = %s\n", opt_plugin_ini); + } + +exit: + return error; +} + + +/** + Check access + + This method checks to ensure all of the directories (opt_basedir, + opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by + the user. + + @retval int error = 1, success = 0 +*/ + +static int check_access() +{ + int error= 0; + + if ((error= my_access(opt_basedir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n", + opt_basedir); + goto exit; + } + if ((error= my_access(opt_plugin_dir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n", + opt_plugin_dir); + goto exit; + } + if ((error= my_access(opt_datadir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n", + opt_datadir); + goto exit; + } + if ((error= my_access(opt_plugin_ini, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", + opt_plugin_ini); + goto exit; + } + +exit: + return error; +} + + +/** + Locate the tool and form tool path. + + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int find_tool(const char *tool_name, char *tool_path) +{ + int i= 0; + + const char *paths[]= { + opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", + }; + for (i= 0; i < (int)array_elements(paths); i++) + { + if (paths[i] && (search_paths(paths[i], tool_name, tool_path))) + goto found; + } + fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name); + return 1; +found: + if (opt_verbose) + printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path); + return 0; +} + + +/** + Find the plugin library. + + This function attempts to use the @c plugin_dir option passed on the + command line to locate the plugin. + + @param[out] tp_path The actual path to plugin with FN_SOEXT applied. + + @retval int error = 1, success = 0 +*/ + +static int find_plugin(char *tp_path) +{ + /* Check for existance of plugin */ + fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0)); + if (!file_exists(tp_path)) + { + fprintf(stderr, "ERROR: The plugin library is missing or in a different" + " location.\n"); + return 1; + } + else if (opt_verbose) + { + printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path); + } + return 0; +} + + +/** + Build the boostrap file. + + Create a new file and populate it with SQL commands to ENABLE or DISABLE + the plugin via INSERT and DELETE operations on the mysql.plugin table. + + param[in] operation The type of operation (ENABLE or DISABLE) + param[out] bootstrap A FILE* pointer + + @retval int error = 1, success = 0 +*/ + +static int build_bootstrap_file(char *operation, char *bootstrap) +{ + int error= 0; + FILE *file= 0; + + /* + Perform plugin operation : ENABLE or DISABLE + + The following creates a temporary bootstrap file and populates it with + the appropriate SQL commands for the operation. For ENABLE, INSERT + statements are created. For DISABLE, DELETE statements are created. The + values for these statements are derived from the plugin_data read from the + .ini configuration file. Once the file is built, a call to + mysqld is made in read only, bootstrap modes to read the SQL statements + and execute them. + */ + if ((error= make_tempfile(bootstrap, "sql"))) + { + /* Fail if we cannot create a temporary file for the bootstrap commands. */ + fprintf(stderr, "ERROR: Cannot create bootstrap file.\n"); + goto exit; + } + if ((file= fopen(bootstrap, "w+")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n"); + error= 1; + goto exit; + } + if (strcasecmp(operation, "enable") == 0) + { + int i= 0; + fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES "); + for (i= 0; i < (int)array_elements(plugin_data.components); i++) + { + /* stop when we read the end of the symbol list - marked with NULL */ + if (plugin_data.components[i] == NULL) + { + break; + } + if (i > 0) + { + fprintf(file, ", "); + } + fprintf(file, "('%s','%s')", + plugin_data.components[i], plugin_data.so_name); + } + fprintf(file, ";\n"); + if (opt_verbose) + { + printf("# Enabling %s...\n", plugin_data.name); + } + } + else + { + fprintf(file, + "DELETE FROM mysql.plugin WHERE name = '%s';", plugin_data.name); + if (opt_verbose) + { + printf("# Disabling %s...\n", plugin_data.name); + } + } + +exit: + fclose(file); + return error; +} + + +/** + Dump bootstrap file. + + Read the contents of the bootstrap file and print it out. + + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int dump_bootstrap_file(char *bootstrap_file) +{ + char *ret= 0; + int error= 0; + char query_str[512]; + FILE *file= 0; + + if ((file= fopen(bootstrap_file, "r")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n"); + error= 1; + goto exit; + } + ret= fgets(query_str, 512, file); + if (ret == 0) + { + fprintf(stderr, "ERROR: Cannot read bootstrap file.\n"); + error= 1; + goto exit; + } + printf("# Query: %s", query_str); + +exit: + if (file) + { + fclose(file); + } + return error; +} + + +/** + Bootstrap the server + + Create a command line sequence to launch mysqld in bootstrap mode. This + will allow mysqld to launch a minimal server instance to read and + execute SQL commands from a file piped in (the boostrap file). We use + the --no-defaults option to skip reading values from the config file. + + The bootstrap mode skips loading of plugins and many other subsystems. + This allows the mysql_plugin tool to insert the correct rows into the + mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once + the server is launched in normal mode, the plugin will be loaded + (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the + (sometimes) complicated LOAD PLUGIN commands. + + @param[in] server_path Path to server executable + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int bootstrap_server(char *server_path, char *bootstrap_file) +{ + char bootstrap_cmd[FN_REFLEN]; + int error= 0; + int ret= 0; + +#ifdef __WIN__ + char *format_str= 0; + char *verbose_str= ""; + + if (opt_verbose) + strcat(verbose_str, "--console"); + if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || + has_spaces(bootstrap_file)) + format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; + else + format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s"; + + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str, + add_quotes(convert_path(server_path)), verbose_str, + add_quotes(opt_datadir), add_quotes(opt_basedir), + add_quotes(bootstrap_file)); +#else + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), + "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" + " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", bootstrap_cmd); + } + error= run_command(bootstrap_cmd, "r"); + if (error) + fprintf(stderr, + "ERROR: Unexpected result from bootstrap. Error code: %d.\n", + ret); + + return error; +} From 6f245ec94c9386fe8ce368ebe67c781dbcb8b809 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 16:27:55 -0400 Subject: [PATCH 008/143] WL#5710 - fixed (c) character causing compile issue. --- client/mysql_plugin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 58ca69ed778..47646a3da81 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* + 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 From cf7c2d84014add29fb704a5cd1ddec6c3f36461c Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 19 Jul 2011 19:18:22 -0400 Subject: [PATCH 009/143] WL#5710 - remove more special characters in mysql_plugin.c. --- client/mysql_plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 47646a3da81..16ed3292c18 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify From 9c99ae189c8e03e3b84241a205b87ab7f098b704 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Thu, 21 Jul 2011 14:37:06 -0400 Subject: [PATCH 010/143] WL#5710 : enable and disable plugins Added additional search paths for finding tools. --- client/mysql_plugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 16ed3292c18..b59a4c6f219 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -924,6 +924,7 @@ static int find_tool(const char *tool_name, char *tool_path) const char *paths[]= { opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", + "/extra", "/extra/debug", "/extra/release" }; for (i= 0; i < (int)array_elements(paths); i++) { From 5d9d54519835d2709b690c969909cb6d81f86ada Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Thu, 21 Jul 2011 17:46:20 -0400 Subject: [PATCH 011/143] WL#5710 : enable and disable plugins Added additional search path of /bin for finding tools. --- client/mysql_plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index b59a4c6f219..630800a4b39 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -924,7 +924,7 @@ static int find_tool(const char *tool_name, char *tool_path) const char *paths[]= { opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", - "/extra", "/extra/debug", "/extra/release" + "/extra", "/extra/debug", "/extra/release", "/bin" }; for (i= 0; i < (int)array_elements(paths); i++) { From 7f8d6ef7d6c31266dca89c457c953326e1b59d8d Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 22 Jul 2011 10:07:45 +0200 Subject: [PATCH 012/143] Bug #11766328 59417: TEST BUGS.BUG57108 IS BROKEN:..... The test has been removed, no other tests are using this file (If any did, they would fail) Removing the file. --- mysql-test/std_data/bug57108.cnf | 95 -------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 mysql-test/std_data/bug57108.cnf diff --git a/mysql-test/std_data/bug57108.cnf b/mysql-test/std_data/bug57108.cnf deleted file mode 100644 index 5fd8c485cf0..00000000000 --- a/mysql-test/std_data/bug57108.cnf +++ /dev/null @@ -1,95 +0,0 @@ -[mysqld] -open-files-limit=1024 -character-set-server=latin1 -connect-timeout=4711 -log-bin-trust-function-creators=1 -key_buffer_size=1M -sort_buffer=256K -max_heap_table_size=1M -loose-innodb_data_file_path=ibdata1:10M:autoextend -loose-innodb_buffer_pool_size=8M -loose-innodb_write_io_threads=2 -loose-innodb_read_io_threads=2 -loose-innodb_log_buffer_size=1M -loose-innodb_log_file_size=5M -loose-innodb_additional_mem_pool_size=1M -loose-innodb_log_files_in_group=2 -slave-net-timeout=120 -log-bin=mysqld-bin -loose-enable-performance-schema -loose-performance-schema-max-mutex-instances=10000 -loose-performance-schema-max-rwlock-instances=10000 -loose-performance-schema-max-table-instances=500 -loose-performance-schema-max-table-handles=1000 -binlog-direct-non-transactional-updates - -[mysql] -default-character-set=latin1 - -[mysqlshow] -default-character-set=latin1 - -[mysqlimport] -default-character-set=latin1 - -[mysqlcheck] -default-character-set=latin1 - -[mysql_upgrade] -default-character-set=latin1 -tmpdir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp - -[mysqld.1] -#!run-master-sh -log-bin=master-bin -loose-enable-performance-schema -basedir=/home/bzr/bugs/b57108-5.5-bugteam -tmpdir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1 -character-sets-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/charsets -lc-messages-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/ -datadir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/data -pid-file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/run/mysqld.1.pid -#host=localhost -port=13000 -socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock -#log-error=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/log/mysqld.1.err -general_log=1 -general_log_file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/mysqld.log -slow_query_log=1 -slow_query_log_file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/mysqld-slow.log -#user=root -#password= -server-id=1 -secure-file-priv=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var -ssl-ca=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/cacert.pem -ssl-cert=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/server-cert.pem -ssl-key=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/server-key.pem - -[mysqlbinlog] -disable-force-if-open -character-sets-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/charsets - -[ENV] -MASTER_MYPORT=13000 -MASTER_MYSOCK=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock - -[client] -password= -user=root -port=13000 -host=localhost -socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock - -[mysqltest] -ssl-ca=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/cacert.pem -ssl-cert=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/client-cert.pem -ssl-key=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/client-key.pem -skip-ssl=1 - -[client.1] -password= -user=root -port=13000 -host=localhost -socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock - From 6c4da66d8307bf139051864fb9def7159e72e2b8 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Mon, 25 Jul 2011 15:30:24 -0400 Subject: [PATCH 013/143] WL#5710: enable and disable plugins This patch corrects a problem found in pushbuild with the stat() method on some platforms. The code was changed to use my_stat() instead. Also adds mysql_plugin to the mysql.spec.sh file for packaging. --- client/mysql_plugin.c | 16 ++++++++-------- support-files/mysql.spec.sh | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 630800a4b39..dd41693161d 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -501,14 +501,13 @@ get_one_option(int optid, static int file_exists(char * filename) { - struct stat buf; - int i = stat (filename, &buf); - /* File found */ - if (i == 0) + MY_STAT stat_arg; + + if (!my_stat(filename, &stat_arg, MYF(0))) { - return 1; + return 0; } - return 0; + return 1; } @@ -924,7 +923,8 @@ static int find_tool(const char *tool_name, char *tool_path) const char *paths[]= { opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", - "/extra", "/extra/debug", "/extra/release", "/bin" + "/extra", "/extra/debug", "/extra/release", "/bin", "/usr/bin", + "/mysql/bin" }; for (i= 0; i < (int)array_elements(paths); i++) { diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index cc4477f2fac..719800e309a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1000,6 +1000,7 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/mysql_setpermission %attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql %attr(755, root, root) %{_bindir}/mysql_upgrade +%attr(755, root, root) %{_bindir}/mysql_plugin %attr(755, root, root) %{_bindir}/mysql_zap %attr(755, root, root) %{_bindir}/mysqlbug %attr(755, root, root) %{_bindir}/mysqld_multi @@ -1017,6 +1018,7 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_sbindir}/rcmysql %attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so %attr(755, root, root) %{_libdir}/mysql/plugin/libdaemon_example.so +%attr(755, root, root) %{_libdir}/mysql/plugin/daemon_example.ini %attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so %attr(755, root, root) %{_libdir}/mysql/plugin/semisync_master.so %attr(755, root, root) %{_libdir}/mysql/plugin/semisync_slave.so @@ -1130,6 +1132,10 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Mon Jul 25 2011 Chuck Bell + +- Added the mysql_plugin client - enables or disables plugins. + * Thu Jul 07 2011 Joerg Bruehe - Fix bug#45415: "rpm upgrade recreates test database" From 341989469f31225646b4fedf9d42a8f73a4d4801 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 28 Jul 2011 12:54:02 +0200 Subject: [PATCH 014/143] Bug #12726039 MTR SHOULD PROVIDE ABILITY TO DISABLE TEST ON SELECTED PLATFORMS Add extra patterns to look for @ --- mysql-test/lib/mtr_cases.pm | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 708b8e90fc4..3dcd99f235f 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -317,10 +317,30 @@ sub collect_one_suite($) my %disabled; if ( open(DISABLED, "$testdir/disabled.def" ) ) { + # $^O on Windows considered not generic enough + my $plat= (IS_WINDOWS) ? 'windows' : $^O; + while ( ) { chomp; - if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) + #diasble the test case if platform matches + if ( /\@/ ) + { + if ( /\@$plat/ ) + { + /^\s*(\S+)\s*\@$plat.*:\s*(.*?)\s*$/ ; + $disabled{$1}= $2; + } + elsif ( /\@!(\S*)/ ) + { + if ( $1 ne $plat) + { + /^\s*(\S+)\s*\@!.*:\s*(.*?)\s*$/ ; + $disabled{$1}= $2; + } + } + } + elsif ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) { $disabled{$1}= $2; } From 730bb779076980ae67460521d94b2cbe96a70a54 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 28 Jul 2011 13:01:51 +0200 Subject: [PATCH 015/143] Fixed test ndb.ndb_partition_error2, didn't include have_ndb.inc --- mysql-test/suite/ndb/t/ndb_partition_error2.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/ndb/t/ndb_partition_error2.test b/mysql-test/suite/ndb/t/ndb_partition_error2.test index afedd0e3c5c..58c38f2dd37 100644 --- a/mysql-test/suite/ndb/t/ndb_partition_error2.test +++ b/mysql-test/suite/ndb/t/ndb_partition_error2.test @@ -1,3 +1,4 @@ +-- source include/have_ndb.inc disable_query_log; --require r/true.require select support = 'Enabled' as `TRUE` from information_schema.engines where engine = 'ndbcluster'; From c671a76a4dd315af1cf3b39e566b788e73a0f161 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Mon, 8 Aug 2011 17:01:09 +0530 Subject: [PATCH 016/143] Recommitting the changes to push the code. --- mysql-test/suite/sys_vars/r/all_vars.result | 6 - .../r/innodb_file_format_check_basic.result | 125 ++++++++++-------- .../r/innodb_file_format_max_basic.result | 65 +++++++++ .../r/innodb_rollback_segments_basic.result | 64 +++++++++ .../r/innodb_stats_method_basic.result | 83 ++++++++++++ .../t/innodb_file_format_check_basic.test | 112 +++++++++++----- .../t/innodb_file_format_max_basic.test | 60 +++++++++ .../t/innodb_rollback_segments_basic.test | 58 ++++++++ .../sys_vars/t/innodb_stats_method_basic.test | 72 ++++++++++ 9 files changed, 551 insertions(+), 94 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test create mode 100644 mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test create mode 100644 mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 3cee368853f..715ad9e2c15 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,13 +11,7 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: -INNODB_ROLLBACK_SEGMENTS -INNODB_STATS_METHOD -INNODB_FILE_FORMAT_MAX INNODB_LARGE_PREFIX -INNODB_ROLLBACK_SEGMENTS -INNODB_STATS_METHOD -INNODB_FILE_FORMAT_MAX INNODB_LARGE_PREFIX drop table t1; drop table t2; diff --git a/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result index c59e1b802f4..9167585f1d6 100644 --- a/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result @@ -1,59 +1,80 @@ -SET @start_global_value = @@global.innodb_file_format_max; +SET @start_global_value = @@global.innodb_file_format_check; SELECT @start_global_value; @start_global_value -Antelope -Valid values are 'Antelope' and 'Barracuda' -select @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); -@@global.innodb_file_format_max in ('Antelope', 'Barracuda') 1 -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope -select @@session.innodb_file_format_max; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable -show global variables like 'innodb_file_format_max'; +Valid values are 'ON' and 'OFF' +SELECT @@global.innodb_file_format_check in (0, 1); +@@global.innodb_file_format_check in (0, 1) +1 +SELECT @@global.innodb_file_format_check; +@@global.innodb_file_format_check +1 +SELECT @@session.innodb_file_format_check; +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +SHOW global variables LIKE 'innodb_file_format_check'; Variable_name Value -innodb_file_format_max Antelope -show session variables like 'innodb_file_format_max'; +innodb_file_format_check ON +SHOW session variables LIKE 'innodb_file_format_check'; Variable_name Value -innodb_file_format_max Antelope -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; +innodb_file_format_check ON +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_check'; VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; +INNODB_FILE_FORMAT_CHECK ON +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_check'; VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -set global innodb_file_format_max='Antelope'; -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -set @@global.innodb_file_format_max='Barracuda'; -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Barracuda -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Barracuda -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Barracuda -set session innodb_file_format_max='Salmon'; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL -set @@session.innodb_file_format_max='Salmon'; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL -set global innodb_file_format_max=1.1; -ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' -set global innodb_file_format_max=1e1; -ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' -set global innodb_file_format_max='Salmon'; -ERROR 42000: Variable 'innodb_file_format_max' can't be set to the value of 'Salmon' -SET @@global.innodb_file_format_max = @start_global_value; -SELECT @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope +INNODB_FILE_FORMAT_CHECK ON +SET @@global.innodb_file_format_check='Off'; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check=1; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check=0; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check='On'; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET session innodb_large_prefix='OFF'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_stats_on_metadata='ON'; +ERROR HY000: Variable 'innodb_stats_on_metadata' is a GLOBAL variable and should be set with SET GLOBAL +SELECT IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +COUNT(@@GLOBAL.innodb_file_format_check) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@innodb_file_format_check = @@GLOBAL.innodb_file_format_check; +@@innodb_file_format_check = @@GLOBAL.innodb_file_format_check +1 +1 Expected +SELECT COUNT(@@innodb_file_format_check); +COUNT(@@innodb_file_format_check) +1 +1 Expected +SELECT COUNT(@@local.innodb_file_format_check); +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_file_format_check); +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +COUNT(@@GLOBAL.innodb_file_format_check) +1 +1 Expected +SELECT innodb_file_format_check = @@SESSION.innodb_file_format_check; +ERROR 42S22: Unknown column 'innodb_file_format_check' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result new file mode 100644 index 00000000000..32b2262c091 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result @@ -0,0 +1,65 @@ +SET @start_global_value = @@global.innodb_file_format_max; +SELECT @start_global_value; +@start_global_value +Antelope +Valid values are 'Antelope' and 'Barracuda' +SELECT @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); +@@global.innodb_file_format_max in ('Antelope', 'Barracuda') +1 +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope +SELECT @@session.innodb_file_format_max; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable +SHOW global variables LIKE 'innodb_file_format_max'; +Variable_name Value +innodb_file_format_max Antelope +SHOW session variables LIKE 'innodb_file_format_max'; +Variable_name Value +innodb_file_format_max Antelope +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SET global innodb_file_format_max='Antelope'; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SET @@global.innodb_file_format_max='Barracuda'; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Barracuda +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Barracuda +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Barracuda +SET session innodb_file_format_max='Salmon'; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_file_format_max='Salmon'; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_file_format_max=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' +SET global innodb_file_format_max=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' +SET global innodb_file_format_max='Salmon'; +ERROR 42000: Variable 'innodb_file_format_max' can't be set to the value of 'Salmon' +SET @@global.innodb_file_format_max = @start_global_value; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope diff --git a/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result b/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result new file mode 100644 index 00000000000..a8d392eee38 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result @@ -0,0 +1,64 @@ +SET @start_global_value = @@global.innodb_rollback_segments; +SELECT @start_global_value; +@start_global_value +128 +Valid values are zero or above +SELECT @@global.innodb_rollback_segments >=0; +@@global.innodb_rollback_segments >=0 +1 +SELECT @@global.innodb_rollback_segments <=128; +@@global.innodb_rollback_segments <=128 +1 +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +128 +SELECT @@session.innodb_rollback_segments; +ERROR HY000: Variable 'innodb_rollback_segments' is a GLOBAL variable +SHOW global variables LIKE 'innodb_rollback_segments'; +Variable_name Value +innodb_rollback_segments 128 +SHOW session variables LIKE 'innodb_rollback_segments'; +Variable_name Value +innodb_rollback_segments 128 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 128 +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 128 +SET global innodb_rollback_segments=100; +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +100 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 100 +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 100 +SET session innodb_rollback_segments=1; +ERROR HY000: Variable 'innodb_rollback_segments' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_rollback_segments=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments="foo"; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments=-7; +Warnings: +Warning 1292 Truncated incorrect innodb_rollback_segments value: '-7' +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +1 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 1 +SET @@global.innodb_rollback_segments = @start_global_value; +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +128 diff --git a/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result b/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result new file mode 100644 index 00000000000..6599ca9edb6 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result @@ -0,0 +1,83 @@ +SET @start_global_value = @@global.innodb_stats_method; +SELECT @start_global_value; +@start_global_value +nulls_equal +Valid values are 'nulls_equal', 'nulls_unequal', 'nulls_ignored' +SELECT @@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored'); +@@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored') +1 +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal +SELECT @@session.innodb_stats_method; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable +SHOW global variables LIKE 'innodb_stats_method'; +Variable_name Value +innodb_stats_method nulls_equal +SHOW session variables LIKE 'innodb_stats_method'; +Variable_name Value +innodb_stats_method nulls_equal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SET global innodb_stats_method='nulls_equal'; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SET @@global.innodb_stats_method='nulls_unequal'; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_unequal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_unequal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_unequal +SET global innodb_stats_method=2; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_ignored +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_ignored +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_ignored +SET session innodb_stats_method='nulls_equal'; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_stats_method='nulls_ignored'; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_stats_method=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_stats_method' +SET global innodb_stats_method=4; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of '4' +SET global innodb_stats_method=-2; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of '-2' +SET global innodb_stats_method=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_stats_method' +SET global innodb_stats_method='some'; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of 'some' +SET @@global.innodb_stats_method = @start_global_value; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal diff --git a/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test index cbf25af2442..f9f61b9380c 100644 --- a/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test @@ -1,55 +1,95 @@ - - -# 2010-01-25 - Added # +# 2011-08-02 - Added +# + --source include/not_embedded.inc --source include/have_innodb.inc -SET @start_global_value = @@global.innodb_file_format_max; +SET @start_global_value = @@global.innodb_file_format_check; SELECT @start_global_value; # # exists as global only # ---echo Valid values are 'Antelope' and 'Barracuda' -select @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); -select @@global.innodb_file_format_max; +--echo Valid values are 'ON' and 'OFF' +SELECT @@global.innodb_file_format_check in (0, 1); +SELECT @@global.innodb_file_format_check; + --error ER_INCORRECT_GLOBAL_LOCAL_VAR -select @@session.innodb_file_format_max; -show global variables like 'innodb_file_format_max'; -show session variables like 'innodb_file_format_max'; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; +SELECT @@session.innodb_file_format_check; +SHOW global variables LIKE 'innodb_file_format_check'; +SHOW session variables LIKE 'innodb_file_format_check'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_check'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_check'; # -# show that it's writable +# show that it's read only # -set global innodb_file_format_max='Antelope'; -select @@global.innodb_file_format_max; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -set @@global.innodb_file_format_max='Barracuda'; -select @@global.innodb_file_format_max; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check='Off'; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check=1; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check=0; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check='On'; +--echo Expected error 'Read only variable' + --error ER_GLOBAL_VARIABLE -set session innodb_file_format_max='Salmon'; +SET session innodb_large_prefix='OFF'; --error ER_GLOBAL_VARIABLE -set @@session.innodb_file_format_max='Salmon'; +SET @@session.innodb_stats_on_metadata='ON'; # -# incorrect types -# ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_file_format_max=1.1; ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_file_format_max=1e1; ---error ER_WRONG_VALUE_FOR_VAR -set global innodb_file_format_max='Salmon'; - -# -# Cleanup +# Check if the value in GLOBAL Table matches value in variable # -SET @@global.innodb_file_format_max = @start_global_value; -SELECT @@global.innodb_file_format_max; +SELECT IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +--echo 1 Expected + +# +# Check if accessing variable with and without GLOBAL point to same variable +# +SELECT @@innodb_file_format_check = @@GLOBAL.innodb_file_format_check; +--echo 1 Expected + +# +# Check if innodb_doublewrite can be accessed with and without @@ sign +# + +SELECT COUNT(@@innodb_file_format_check); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_file_format_check); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_file_format_check); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_file_format_check = @@SESSION.innodb_file_format_check; +--echo Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test new file mode 100644 index 00000000000..c2cb4cb47bb --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test @@ -0,0 +1,60 @@ +# +# 2011-08-02 - Added +# +--source include/not_embedded.inc +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_file_format_max; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'Antelope' and 'Barracuda' +SELECT @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); +SELECT @@global.innodb_file_format_max; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_file_format_max; +SHOW global variables LIKE 'innodb_file_format_max'; +SHOW session variables LIKE 'innodb_file_format_max'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; + +# +# show that it's writable +# +SET global innodb_file_format_max='Antelope'; +SELECT @@global.innodb_file_format_max; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +SET @@global.innodb_file_format_max='Barracuda'; +SELECT @@global.innodb_file_format_max; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +--error ER_GLOBAL_VARIABLE +SET session innodb_file_format_max='Salmon'; +--error ER_GLOBAL_VARIABLE +SET @@session.innodb_file_format_max='Salmon'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_file_format_max=1.1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_file_format_max=1e1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_file_format_max='Salmon'; + +# +# Cleanup +# + +SET @@global.innodb_file_format_max = @start_global_value; +SELECT @@global.innodb_file_format_max; diff --git a/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test b/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test new file mode 100644 index 00000000000..9f0b70a528f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test @@ -0,0 +1,58 @@ +# +# 2011-08-01 Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_rollback_segments; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are zero or above +SELECT @@global.innodb_rollback_segments >=0; +SELECT @@global.innodb_rollback_segments <=128; +SELECT @@global.innodb_rollback_segments; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_rollback_segments; +SHOW global variables LIKE 'innodb_rollback_segments'; +SHOW session variables LIKE 'innodb_rollback_segments'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; + +# +# show that it's writable +# +SET global innodb_rollback_segments=100; +SELECT @@global.innodb_rollback_segments; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +--error ER_GLOBAL_VARIABLE +SET session innodb_rollback_segments=1; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments=1.1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments=1e1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments="foo"; +SET global innodb_rollback_segments=-7; +SELECT @@global.innodb_rollback_segments; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; + +# +# cleanup +# + +SET @@global.innodb_rollback_segments = @start_global_value; +SELECT @@global.innodb_rollback_segments; diff --git a/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test b/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test new file mode 100644 index 00000000000..f01574c3683 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test @@ -0,0 +1,72 @@ +# +# 2011-08-05 - Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_stats_method; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'nulls_equal', 'nulls_unequal', 'nulls_ignored' +SELECT @@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored'); +SELECT @@global.innodb_stats_method; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_stats_method; +SHOW global variables LIKE 'innodb_stats_method'; +SHOW session variables LIKE 'innodb_stats_method'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; + +# +# show that it's writable +# +SET global innodb_stats_method='nulls_equal'; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +SET @@global.innodb_stats_method='nulls_unequal'; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +SET global innodb_stats_method=2; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; + +--error ER_GLOBAL_VARIABLE +SET session innodb_stats_method='nulls_equal'; +--error ER_GLOBAL_VARIABLE +SET @@session.innodb_stats_method='nulls_ignored'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_stats_method=1.1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method=4; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method=-2; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_stats_method=1e1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method='some'; + +# +# Cleanup +# + +SET @@global.innodb_stats_method = @start_global_value; +SELECT @@global.innodb_stats_method; From 99f2e85b6cefa8e864a5099324301d110aa3048b Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 9 Aug 2011 08:58:18 -0400 Subject: [PATCH 017/143] WL#5710 : enable and disable plugins This patch corrects a problem found in PB. Some platforms have very different locations for the mysql installation. The client was not able to find either my_print_defaults or mysqld predictably. The patch adds two new command options --mysqld and --my-print-defaults which can be used to provide the location of mysqld and my_print_defaults by providing the paths. The patch also changes the concatenation of the soname extension to fix a problem found on some Ubuntu systems. The patch contains changes to the test to ensure it will run on all platforms. A trap is set in the test to skip testing if the location of mysqld, my_print_defaults, or the daemon_example.ini files cannot be determined. --- client/mysql_plugin.c | 58 ++++++++-- mysql-test/r/mysql_plugin.result | 12 ++ mysql-test/t/mysql_plugin.test | 188 ++++++++++++++++++++++--------- 3 files changed, 193 insertions(+), 65 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index dd41693161d..6679fa9ca6f 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -35,7 +35,8 @@ static uint opt_verbose=0; static uint opt_no_defaults= 0; static uint opt_print_defaults= 0; static char *opt_datadir=0, *opt_basedir=0, - *opt_plugin_dir=0, *opt_plugin_ini=0; + *opt_plugin_dir=0, *opt_plugin_ini=0, + *opt_mysqld=0, *opt_my_print_defaults=0; static char bootstrap[FN_REFLEN]; @@ -66,6 +67,11 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"print-defaults", 'P', "Show default values from configuration file.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"my-print-defaults", 'f', "Path to my_print_defaults executable. " + "Example: /source/temp11/extra", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "More verbose output; you can use this multiple times to get even more " "verbose output.", @@ -317,6 +323,7 @@ static int get_default_values() int ret= 0; FILE *file= 0; + bzero(tool_path, FN_REFLEN); if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) goto exit; else @@ -335,6 +342,10 @@ static int get_default_values() snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, add_quotes(tool_path), add_quotes(defaults_file)); + if (opt_verbose) + { + printf("# my_print_defaults found: %s\n", tool_path); + } } #else snprintf(defaults_cmd, sizeof(defaults_cmd), @@ -438,6 +449,14 @@ static void print_default_values(void) { printf("--plugin_ini=%s ", opt_plugin_ini); } + if (opt_mysqld) + { + printf("--mysqld=%s ", opt_mysqld); + } + if (opt_my_print_defaults) + { + printf("--my_print_defaults=%s ", opt_my_print_defaults); + } printf("\n"); } @@ -486,6 +505,12 @@ get_one_option(int optid, case 'i': opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); break; + case 'm': + opt_mysqld= my_strdup(argument, MYF(MY_FAE)); + break; + case 'f': + opt_my_print_defaults= my_strdup(argument, MYF(MY_FAE)); + break; } return 0; } @@ -526,10 +551,11 @@ static int search_dir(const char * base_path, const char *tool_name, const char *subdir, char *tool_path) { char new_path[FN_REFLEN]; + char source_path[FN_REFLEN]; - strcpy(new_path, base_path); - strcat(new_path, subdir); - fn_format(new_path, new_path, "", tool_name, MY_UNPACK_FILENAME); + strcpy(source_path, base_path); + strcat(source_path, subdir); + fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME); if (file_exists(new_path)) { strcpy(tool_path, new_path); @@ -634,10 +660,10 @@ static int load_plugin_data(char *plugin_name, char *config_file) } if (i == -1) // if first pass, read this line as so_name { - /* save so_name */ - plugin_data.so_name= my_strdup(line, MYF(MY_WME)); /* Add proper file extension for soname */ - strcat((char *)plugin_data.so_name, FN_SOEXT); + strcat(line, FN_SOEXT); + /* save so_name */ + plugin_data.so_name= my_strdup(line, MYF(MY_WME|MY_ZEROFILL)); i++; } else @@ -902,6 +928,18 @@ static int check_access() opt_plugin_ini); goto exit; } + if ((error= my_access(opt_mysqld, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n", + opt_mysqld); + goto exit; + } + if ((error= my_access(opt_my_print_defaults, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n", + opt_my_print_defaults); + goto exit; + } exit: return error; @@ -922,9 +960,9 @@ static int find_tool(const char *tool_name, char *tool_path) int i= 0; const char *paths[]= { - opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share", - "/extra", "/extra/debug", "/extra/release", "/bin", "/usr/bin", - "/mysql/bin" + opt_basedir, opt_mysqld, opt_my_print_defaults, "/usr", + "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug", + "/extra/release", "/bin", "/usr/bin", "/mysql/bin" }; for (i= 0; i < (int)array_elements(paths); i++) { diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result index 1a39c86ab9a..949f3748236 100644 --- a/mysql-test/r/mysql_plugin.result +++ b/mysql-test/r/mysql_plugin.result @@ -49,6 +49,14 @@ ERROR: Cannot access basedir at '/basedir_not_there/'. # ERROR: Cannot read plugin config file daemon_example. File does not exist. # +# Attempt to use bad paths - mysqld +# +ERROR: Cannot access mysqld path '/mysqld_not_there/'. +# +# Attempt to use bad paths - my_print_defaults +# +ERROR: Cannot access my-print-defaults path '/my_print_defaults_not_there/'. +# # Missing library # ERROR: The plugin library is missing or in a different location. @@ -90,6 +98,10 @@ Options: -n, --no-defaults Do not read values from configuration file. -P, --print-defaults Show default values from configuration file. + -m, --mysqld=name Path to mysqld executable. Example: /sbin/temp1/mysql/bin + -f, --my-print-defaults=name + Path to my_print_defaults executable. Example: + /source/temp11/extra -v, --verbose More verbose output; you can use this multiple times to get even more verbose output. -V, --version Output version information and exit. diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index b90619774df..cad89d9de7a 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -1,35 +1,107 @@ # # Test mysql_plugin tool # +# This test contains test cases for testing the mysql_plugin client with +# the daemon_example plugin. Test cases include tests for: +# +# - successful enable/disable +# - incorrect paths +# - missing paths/options +# +# Implementation Notes +# +# The mysql_plugin tool now accepts --mysqld the path to mysqld server. The +# mysqld path is extracted from MYSQLD_BOOTSTRAP_CMD line. We also extract +# the path of MYSQLD_BASEDIR (where mysql exists) and use it for the errmsg +# file. The directories differ between Windows and Unix but the Perl script +# included below will pick as per platform. +# +# The test is also designed to issue the --skip directive if the location of +# the mysqld, my_print_defaults, or daemon_example.ini files cannot be found. +# --source include/not_embedded.inc # Add the datadir, basedir, plugin_dir to the bootstrap command let $MYSQLD_DATADIR= `select @@datadir`; let $MYSQL_BASEDIR= `select @@basedir`; +let $MYSQL_ERRMSG_BASEDIR=`select @@lc_messages_dir`; +let $PLUGIN_DIR=`select @@plugin_dir`; -# The mysql_plugin tool expects all executables in "basedir", so they will be copied to it. -# It also expects a directory structure like in the installed mysql version, so errmsg.sys -# will be copied to "basedir/share". The directories differ between Windows and Unix. --disable_abort_on_error -if(`SELECT CONVERT(@@version_compile_os USING latin1) - IN ('Win32','Win64','Windows')`) + +# Perl script to extract the location of the basedir from environment +# variables. This is needed to ensure the test will run on the PB machines +# designed to test release as well as debug builds. It also checks for the +# location of the my_print_defaults and daemon_example.ini files. + +perl; +use File::Basename; + my ($mysqld)= split " ", $ENV{MYSQLD_BOOTSTRAP_CMD}; + my $mysqld_basedir=dirname($mysqld); + my $my_print_defaults= $ENV{MYSQL_MY_PRINT_DEFAULTS}; + my $my_print_defaults_basedir=dirname($my_print_defaults); + my $daemonexample_ini= "$ENV{DAEMONEXAMPLE_DIR}/daemon_example.ini"; + my $plugindir_ini= "$ENV{PLUGIN_DIR}/daemon_example.ini"; + my $notfound= ""; + open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/mysqld.inc") or die; + print FILE "let \$MYSQLD= $mysqld;\n"; + print FILE "let \$MYSQLD_BASEDIR= $mysqld_basedir;\n"; + print FILE "let \$MYSQL_MY_PRINT_DEFAULTS_BASEDIR= $my_print_defaults_basedir;\n"; + if ((!-e $daemonexample_ini) || (!-r $daemonexample_ini)) + { + print FILE "let \$DAEMONEXAMPLE_DIR= $not_found;\n"; + } + if ((!-e $plugindir_ini) || (!-r $plugindir_ini)) + { + print FILE "let \$PLUGIN_DIR= $not_found;\n"; + } + close FILE; +EOF + + +source $MYSQL_TMP_DIR/mysqld.inc; +remove_file $MYSQL_TMP_DIR/mysqld.inc; + +# The mysql_plugin tool expects a directory structure like in the installed +# mysql version, so errmsg.sys will be copied to "basedir/share", we create +# and remove this structure. + +--mkdir $MYSQLD_BASEDIR/share +--mkdir $MYSQLD_BASEDIR/share/mysql +--copy_file $MYSQL_ERRMSG_BASEDIR/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys +--copy_file $MYSQL_ERRMSG_BASEDIR/english/errmsg.sys $MYSQLD_BASEDIR/share/mysql/errmsg.sys + +# The mysql_plugin tool now accepts --my-print-defaults which points to the +# executable my_print_defaults.exe we can get this path from the variable +# $MYSQL_MY_PRINT_DEFAULTS. + +# Check for my_print_defaults location. Skip if not found. +if ($MYSQL_MY_PRINT_DEFAULTS_BASEDIR == '') { - let $MYSQLD_BASEDIR= $MYSQL_BASEDIR/sql/Debug; - --copy_file $MYSQL_BASEDIR/extra/Debug/my_print_defaults.exe $MYSQLD_BASEDIR/my_print_defaults.exe - --mkdir $MYSQLD_BASEDIR/share - --copy_file $MYSQL_BASEDIR/sql/share/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys - --copy_file $MYSQL_BASEDIR/plugin/daemon_example/daemon_example.ini $DAEMONEXAMPLE_DIR/daemon_example.ini -} -if (`SELECT CONVERT(@@version_compile_os USING latin1) - NOT IN ('Win32','Win64','Windows')`) -{ - let $MYSQLD_BASEDIR= $MYSQL_BASEDIR/sql; - --copy_file $MYSQL_BASEDIR/extra/my_print_defaults $MYSQLD_BASEDIR/my_print_defaults - --copy_file $MYSQL_BASEDIR/sql/share/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys + --skip Test requires known location of my_print_defaults executable. } -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; +# Check for mysqld location. Skip if not found. +if ($MYSQLD == '') +{ + --skip Test requires known location of mysqld executable. +} + +# Check for daemon_example.ini location. Skip if not found in either +# the plugin_dir path or the daemon_example_dir path. +if ($PLUGIN_DIR == '') +{ + if ($DAEMONEXAMPLE_DIR == '') + { + --skip Test requires known location of daemon_example.ini file. + } + let $PLUGIN_DIR = $DAEMONEXAMPLE_DIR; +} + +# Build client command for reuse. + +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --echo # --echo # Ensure the plugin isn't loaded. @@ -52,11 +124,11 @@ EOF # # Enable the plugin # ---exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example +--exec $MYSQL_PLUGIN_CMD ENABLE daemon_example # # Ensure enabling an enabled plugin doesn't fail ---exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example +--exec $MYSQL_PLUGIN_CMD ENABLE daemon_example # # Restart the server @@ -88,7 +160,7 @@ EOF # # Disable the plugin # ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example # # Restart the server @@ -121,81 +193,96 @@ EOF --echo # Attempt to load non-existant plugin --echo # --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE NOT_THERE_AT_ALL 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE NOT_THERE_AT_ALL 2>&1 --echo # --echo # Attempt to use non-existant plugin.ini file --echo # --error 1,2,7,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1 --echo # --echo # Attempt to omit the plugin --echo # --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE 2>&1 --echo # --echo # Attempt to omit DISABLE|ENABLE --echo # --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD daemon_example 2>&1 --echo # --echo # Attempt to use bad paths - datadir --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Attempt to use bad paths - basedir --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Attempt to use bad paths - plugin_dir --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=/plugin_not_there/; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=/plugin_not_there/ --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - mysqld +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=/mysqld_not_there/ --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - my_print_defaults +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=/my_print_defaults_not_there/; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + --echo # --echo # Missing library --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Bad format for config file --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing base_dir option --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing data_dir option --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQLD_BASEDIR --plugin-dir=$DAEMONEXAMPLE_DIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing plugin_dir option --echo # -let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQL_BASEDIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 ---exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Show the help. @@ -223,18 +310,9 @@ EOF --error 0,1 --remove_file $expect_file -if(`SELECT CONVERT(@@version_compile_os USING latin1) - IN ('Win32','Win64','Windows')`) -{ - --remove_file $DAEMONEXAMPLE_DIR/daemon_example.ini - --remove_file $MYSQLD_BASEDIR/my_print_defaults.exe - --remove_file $MYSQLD_BASEDIR/share/errmsg.sys - --rmdir $MYSQLD_BASEDIR/share -} -if(`SELECT CONVERT(@@version_compile_os USING latin1) - NOT IN ('Win32','Win64','Windows')`) -{ - --remove_file $MYSQLD_BASEDIR/my_print_defaults - --remove_file $MYSQLD_BASEDIR/share/errmsg.sys -} +# Cleanup the share folder in the binary path. +--remove_file $MYSQLD_BASEDIR/share/errmsg.sys +--rmdir $MYSQLD_BASEDIR/share/mysql +--rmdir $MYSQLD_BASEDIR/share + --enable_abort_on_error From 1b730666d4a1e3874741a472b7c125bc5d704dd8 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Tue, 9 Aug 2011 15:09:28 -0400 Subject: [PATCH 018/143] WL#5710 : enable and disable plugins This patch corrects an error in the test to ensure the proper path is used for the --mysqld option. --- mysql-test/t/mysql_plugin.test | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index cad89d9de7a..9e71db1a451 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -101,7 +101,7 @@ if ($PLUGIN_DIR == '') # Build client command for reuse. -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --echo # --echo # Ensure the plugin isn't loaded. @@ -216,21 +216,21 @@ EOF --echo # --echo # Attempt to use bad paths - datadir --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Attempt to use bad paths - basedir --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Attempt to use bad paths - plugin_dir --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=/plugin_not_there/ --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=/plugin_not_there/ --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 @@ -244,7 +244,7 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYS --echo # --echo # Attempt to use bad paths - my_print_defaults --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=/my_print_defaults_not_there/; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=/my_print_defaults_not_there/; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 @@ -252,35 +252,35 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYS --echo # --echo # Missing library --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Bad format for config file --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing base_dir option --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing data_dir option --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 --echo # --echo # Missing plugin_dir option --echo # -let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQL_BASEDIR --mysqld=$MYSQLD --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQL_BASEDIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; --error 1,2,139,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 From 00dad1c086a3dfedb36af237ba324925831f22c4 Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Thu, 11 Aug 2011 09:34:16 +0100 Subject: [PATCH 019/143] maintain behavior introduced in fix for MySQL bug 35765 (avert regression) --- sql/sql_yacc.yy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ff2f2a8f273..700995d5bb6 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5036,8 +5036,7 @@ create_table_option: ENGINE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; - if ($3) - Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; + Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; } | MAX_ROWS opt_equal ulonglong_num { @@ -6748,6 +6747,11 @@ alter_list_item: { LEX *lex=Lex; lex->alter_info.flags|= ALTER_OPTIONS; + if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && + !lex->create_info.db_type) + { + lex->create_info.used_fields&= ~HA_CREATE_USED_ENGINE; + } } | FORCE_SYM { From ea4de078af914cd89d3414c62f197c32e73353d7 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Thu, 11 Aug 2011 19:58:49 +0400 Subject: [PATCH 020/143] Fix for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR CERTAIN QUERIES TO INFORMATION_SCHEMA". The problem was that metadata locking subsystem introduced too much overhead for queries to I_S which were processed by opening only .FRM or .TRG files and had to scanned a lot of tables (e.g. SELECT COUNT(*) FROM I_S.TRIGGERS was affected). The same effect was not observed for similar queries which performed full-blown table open in order to fill I_S table. The problem stemmed from the fact that in case when I_S implementation opened only .FRM or .TRG file for each table processed it didn't release metadata lock it has acquired on the table after finishing its processing. As result, list of acquired metadata locks were growing until the end of statement. Since acquisition of each new lock required search in the list of already acquired locks performance degraded. The same effect is not observed when I_S implementation performs full-blown table open for each table being processed, as in the latter cases metadata lock on the table is released right after table processing. This fix addressed the problem by ensuring that I_S implementation releases metadata lock after processing the table in both cases of full-blown table open and in case when only .FRM or .TRG file is read. mysql-test/r/information_schema.result: Added coverage for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR CERTAIN QUERIES TO INFORMATION_SCHEMA". mysql-test/t/information_schema.test: Added coverage for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR CERTAIN QUERIES TO INFORMATION_SCHEMA". sql/sql_show.cc: Changed fill_schema_table_from_frm() to release metadata lock it has acquired after processing the .FRM or .TRG file for table. Without this step metadata locks acquired for each table processed will be accumulated. In situation when a lot of tables are processed by I_S query this will result in transaction with too many metadata locks. As result performance of acquisition of new lock will degrade. --- mysql-test/r/information_schema.result | 114 ++++++++++++++++ mysql-test/t/information_schema.test | 182 ++++++++++++++++++++++++- sql/sql_show.cc | 33 ++++- 3 files changed, 322 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 1418af5b813..88a56edbb5c 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1849,5 +1849,119 @@ unlock tables; drop table t1; drop view v1; # +# Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR +# CERTAIN QUERIES TO INFORMATION_SCHEMA". +# +# Check that metadata locks which are acquired during the process +# of opening tables/.FRMs/.TRG files while filling I_S table are +# not kept to the end of statement. Keeping the locks has caused +# performance problems in cases when big number of tables (.FRMs +# or .TRG files) were scanned as cost of new lock acquisition has +# increased linearly. +drop database if exists mysqltest; +create database mysqltest; +use mysqltest; +create table t0 (i int); +create table t1 (j int); +create table t2 (k int); +# +# Test that we don't keep locks in case when we to fill +# I_S table we perform full-blown table open. +# +# Acquire lock on 't2' so upcoming RENAME is +# blocked. +lock tables t2 read; +# +# Switching to connection 'con12828477_1'. +# +# The below RENAME should wait on 't2' while +# keeping X lock on 't1'. +rename table t1 to t3, t2 to t1, t3 to t2; +# +# Switching to connection 'con12828477_2'. +# +# Wait while the above RENAME is blocked. +# Issue query to I_S which will open 't0' and get +# blocked on 't1' because of RENAME. +select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'; +# +# Switching to connection 'con12828477_3'. +# +# Wait while the above SELECT is blocked. +# +# Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; +# +# Switching to connection 'default'. +# +# +# Unblock the first RENAME. +unlock tables; +# +# Switching to connection 'con12828477_1'. +# +# Reap the first RENAME +# +# Switching to connection 'con12828477_2'. +# +# Reap SELECT to I_S. +table_name auto_increment +t0 NULL +t1 NULL +t2 NULL +# +# Switching to connection 'default'. +# +# +# Now test that we don't keep locks in case when we to fill +# I_S table we read .FRM or .TRG file only (this was the case +# for which problem existed). +# +rename table t4 to t0; +# Acquire lock on 't2' so upcoming RENAME is +# blocked. +lock tables t2 read; +# +# Switching to connection 'con12828477_1'. +# +# The below RENAME should wait on 't2' while +# keeping X lock on 't1'. +rename table t1 to t3, t2 to t1, t3 to t2; +# +# Switching to connection 'con12828477_2'. +# +# Wait while the above RENAME is blocked. +# Issue query to I_S which will open 't0' and get +# blocked on 't1' because of RENAME. +select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'; +# +# Switching to connection 'con12828477_3'. +# +# Wait while the above SELECT is blocked. +# +# Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; +# +# Switching to connection 'default'. +# +# +# Unblock the first RENAME. +unlock tables; +# +# Switching to connection 'con12828477_1'. +# +# Reap the first RENAME +# +# Switching to connection 'con12828477_2'. +# +# Reap SELECT to I_S. +event_object_table trigger_name +# +# Switching to connection 'default'. +# +# +# Clean-up. +drop database mysqltest; +# # End of 5.5 tests # diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 589bb898d6a..e6dc989bdb9 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1543,8 +1543,6 @@ DROP TABLE t1, information_schema.tables; LOCK TABLES t1 READ, information_schema.tables READ; DROP TABLE t1; -# Wait till all disconnects are completed ---source include/wait_until_count_sessions.inc # # Bug #43834 Assertion in Natural_join_column::db_name() on an I_S query @@ -1608,6 +1606,186 @@ drop table t1; drop view v1; +--echo # +--echo # Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR +--echo # CERTAIN QUERIES TO INFORMATION_SCHEMA". +--echo # +--echo # Check that metadata locks which are acquired during the process +--echo # of opening tables/.FRMs/.TRG files while filling I_S table are +--echo # not kept to the end of statement. Keeping the locks has caused +--echo # performance problems in cases when big number of tables (.FRMs +--echo # or .TRG files) were scanned as cost of new lock acquisition has +--echo # increased linearly. +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +use mysqltest; +create table t0 (i int); +create table t1 (j int); +create table t2 (k int); + +--echo # +--echo # Test that we don't keep locks in case when we to fill +--echo # I_S table we perform full-blown table open. +--echo # + +--echo # Acquire lock on 't2' so upcoming RENAME is +--echo # blocked. +lock tables t2 read; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connect (con12828477_1, localhost, root,,mysqltest); +--echo # The below RENAME should wait on 't2' while +--echo # keeping X lock on 't1'. +--send rename table t1 to t3, t2 to t1, t3 to t2 + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connect (con12828477_2, localhost, root,,mysqltest); +--echo # Wait while the above RENAME is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t3, t2 to t1, t3 to t2"; +--source include/wait_condition.inc + +--echo # Issue query to I_S which will open 't0' and get +--echo # blocked on 't1' because of RENAME. +--send select table_name, auto_increment from information_schema.tables where table_schema='mysqltest' + +--echo # +--echo # Switching to connection 'con12828477_3'. +--echo # +connect (con12828477_3, localhost, root,,mysqltest); +--echo # Wait while the above SELECT is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'"; +--source include/wait_condition.inc + +--echo # +--echo # Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +--echo # +--echo # Unblock the first RENAME. +unlock tables; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # Reap the first RENAME +--reap + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Reap SELECT to I_S. +--reap + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; + +--echo # +--echo # Now test that we don't keep locks in case when we to fill +--echo # I_S table we read .FRM or .TRG file only (this was the case +--echo # for which problem existed). +--echo # + +rename table t4 to t0; +--echo # Acquire lock on 't2' so upcoming RENAME is +--echo # blocked. +lock tables t2 read; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # The below RENAME should wait on 't2' while +--echo # keeping X lock on 't1'. +--send rename table t1 to t3, t2 to t1, t3 to t2 + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Wait while the above RENAME is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t3, t2 to t1, t3 to t2"; +--source include/wait_condition.inc + +--echo # Issue query to I_S which will open 't0' and get +--echo # blocked on 't1' because of RENAME. +--send select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest' + +--echo # +--echo # Switching to connection 'con12828477_3'. +--echo # +connection con12828477_3; +--echo # Wait while the above SELECT is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'"; +--source include/wait_condition.inc + +--echo # +--echo # Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +--echo # +--echo # Unblock the first RENAME. +unlock tables; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # Reap the first RENAME +--reap + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Reap SELECT to I_S. +--reap + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +disconnect con12828477_1; +disconnect con12828477_2; +disconnect con12828477_3; + +--echo # +--echo # Clean-up. +drop database mysqltest; + + --echo # --echo # End of 5.5 tests --echo # + +# Wait till all disconnects are completed +--source include/wait_until_count_sessions.inc diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fb5ed62ecdf..887115b38ad 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3157,6 +3157,10 @@ end: */ thd->temporary_tables= NULL; close_thread_tables(thd); + /* + Release metadata lock we might have acquired. + See comment in fill_schema_table_from_frm() for details. + */ thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp); thd->lex= old_lex; @@ -3339,6 +3343,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table, @param[in] db_name database name @param[in] table_name table name @param[in] schema_table_idx I_S table index + @param[in] open_tables_state_backup Open_tables_state object which is used + to save/restore original state of metadata + locks. @param[in] can_deadlock Indicates that deadlocks are possible due to metadata locks, so to avoid them we should not wait in case if @@ -3356,6 +3363,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables, LEX_STRING *db_name, LEX_STRING *table_name, enum enum_schema_tables schema_table_idx, + Open_tables_backup *open_tables_state_backup, bool can_deadlock) { TABLE *table= tables->table; @@ -3501,13 +3509,27 @@ end_share: end_unlock: mysql_mutex_unlock(&LOCK_open); - /* - Don't release the MDL lock, it can be part of a transaction. - If it is not, it will be released by the call to - MDL_context::rollback_to_savepoint() in the caller. - */ end: + /* + Release metadata lock we might have acquired. + + Without this step metadata locks acquired for each table processed + will be accumulated. In situation when a lot of tables are processed + by I_S query this will result in transaction with too many metadata + locks. As result performance of acquisition of new lock will suffer. + + Of course, the fact that we don't hold metadata lock on tables which + were processed till the end of I_S query makes execution less isolated + from concurrent DDL. Consequently one might get 'dirty' results from + such a query. But we have never promised serializability of I_S queries + anyway. + + We don't have any tables open since we took backup, so rolling back to + savepoint is safe. + */ + DBUG_ASSERT(thd->open_tables == NULL); + thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp); thd->clear_error(); return res; } @@ -3758,6 +3780,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) int res= fill_schema_table_from_frm(thd, tables, schema_table, db_name, table_name, schema_table_idx, + &open_tables_state_backup, can_deadlock); thd->pop_internal_handler(); From dfbe4b3367567e1e02b02bba9e57613a072850b6 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 12 Aug 2011 12:49:38 +0200 Subject: [PATCH 021/143] Small followup fix to WL 5710: Test mysql_plugin failed if version string ended in -mN --- mysql-test/t/mysql_plugin.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 9e71db1a451..b07ce40e43a 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -288,11 +288,11 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQ --echo # Show the help. --echo # replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ --exec $MYSQL_PLUGIN --help replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ --exec $MYSQL_PLUGIN --version # From a79cabcfefbf79648597c65de559880f78ae0563 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 14:20:17 +0300 Subject: [PATCH 022/143] bumped the version to 5.1.60 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 0e336c5522b..e56a18540b5 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.59], [], [mysql]) +AC_INIT([MySQL Server], [5.1.60], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 189f235666afbb53ef0a6d0c922c7833a337d4af Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 15:55:04 +0300 Subject: [PATCH 023/143] re-commit of bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM AUTHENTICATION SETTINGS to the release clone. --- mysql-test/r/plugin_auth.result | 22 +++++++++++++++++++++- mysql-test/t/plugin_auth.test | 31 +++++++++++++++++++++++++++++++ sql/sql_acl.cc | 10 +++++----- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/plugin_auth.result b/mysql-test/r/plugin_auth.result index 327ba2969e9..64bc870a7fa 100644 --- a/mysql-test/r/plugin_auth.result +++ b/mysql-test/r/plugin_auth.result @@ -44,7 +44,7 @@ ERROR 28000: Access denied for user 'plug'@'localhost' (using password: YES) ## test correct default plugin select USER(),CURRENT_USER(); USER() CURRENT_USER() -plug@localhost plug@% +plug@localhost plug_dest@% ## test no_auto_create_user sql mode with plugin users SET @@sql_mode=no_auto_create_user; GRANT INSERT ON TEST.* TO grant_user IDENTIFIED WITH 'test_plugin_server'; @@ -462,4 +462,24 @@ CREATE USER bug12610784@localhost; SET PASSWORD FOR bug12610784@localhost = PASSWORD('secret'); ERROR 28000: Access denied for user 'bug12610784'@'localhost' (using password: NO) DROP USER bug12610784@localhost; +# +# Bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM +# AUTHENTICATION SETTINGS +# +CREATE USER bug12818542@localhost +IDENTIFIED WITH 'test_plugin_server' AS 'bug12818542_dest'; +CREATE USER bug12818542_dest@localhost +IDENTIFIED BY 'bug12818542_dest_passwd'; +GRANT PROXY ON bug12818542_dest@localhost TO bug12818542@localhost; +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +bug12818542@localhost bug12818542_dest@localhost +SET PASSWORD = PASSWORD('bruhaha'); +Warnings: +Note 1699 SET PASSWORD has no significance for users authenticating via plugins +SELECT USER(),CURRENT_USER(); +USER() CURRENT_USER() +bug12818542@localhost bug12818542_dest@localhost +DROP USER bug12818542@localhost; +DROP USER bug12818542_dest@localhost; End of 5.5 tests diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index 0dc3068de61..f169360cf2e 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -540,4 +540,35 @@ connection default; disconnect b12610784; DROP USER bug12610784@localhost; + +--echo # +--echo # Bug #12818542: PAM: ADDING PASSWORD FOR AN ACCOUNT DISABLES PAM +--echo # AUTHENTICATION SETTINGS +--echo # + +CREATE USER bug12818542@localhost + IDENTIFIED WITH 'test_plugin_server' AS 'bug12818542_dest'; +CREATE USER bug12818542_dest@localhost + IDENTIFIED BY 'bug12818542_dest_passwd'; +GRANT PROXY ON bug12818542_dest@localhost TO bug12818542@localhost; + +connect(bug12818542_con,localhost,bug12818542,bug12818542_dest); +connection bug12818542_con; +SELECT USER(),CURRENT_USER(); + +SET PASSWORD = PASSWORD('bruhaha'); + +connection default; +disconnect bug12818542_con; + +connect(bug12818542_con2,localhost,bug12818542,bug12818542_dest); +connection bug12818542_con2; +SELECT USER(),CURRENT_USER(); + +connection default; +disconnect bug12818542_con2; + +DROP USER bug12818542@localhost; +DROP USER bug12818542_dest@localhost; + --echo End of 5.5 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f4d217c85ff..06a67edda36 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1881,17 +1881,17 @@ bool change_password(THD *thd, const char *host, const char *user, goto end; } + /* update loaded acl entry: */ + set_user_salt(acl_user, new_password, new_password_len); + if (my_strcasecmp(system_charset_info, acl_user->plugin.str, native_password_plugin_name.str) && my_strcasecmp(system_charset_info, acl_user->plugin.str, old_password_plugin_name.str)) - { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN)); - } - /* update loaded acl entry: */ - set_user_salt(acl_user, new_password, new_password_len); - set_user_plugin(acl_user, new_password_len); + else + set_user_plugin(acl_user, new_password_len); if (update_user_table(thd, table, acl_user->host.hostname ? acl_user->host.hostname : "", From afe0cb3faa979cc2434a4caad4b474b8d40cb34f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 15:56:36 +0300 Subject: [PATCH 024/143] re-commit of Bug #11765565: 58548: 5.5.X NEEDS TO LINK TO THE CORESERVICES FRAMEWORK FOR SOME PLUGINS TO WORK to the 5.5.16 release clone. --- sql/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index f95cc359439..fb86d1ce60f 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -100,6 +100,14 @@ ENDIF() MYSQL_ADD_EXECUTABLE(mysqld ${MYSQLD_SOURCE} DESTINATION ${INSTALL_SBINDIR} COMPONENT Server) +IF(APPLE) + # Add CoreServices framework since some dloadable plugins may need it + FIND_LIBRARY(CORESERVICES NAMES CoreServices) + IF(CORESERVICES) + TARGET_LINK_LIBRARIES(mysqld ${CORESERVICES}) + ENDIF() +ENDIF() + IF(NOT WITHOUT_DYNAMIC_PLUGINS) SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE) GET_TARGET_PROPERTY(mysqld_link_flags mysqld LINK_FLAGS) From 84db3fb472ac52f5fc20e51669b7e8bd221d6801 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 16:50:04 +0300 Subject: [PATCH 025/143] Bug #12777649: "OS THREAD ID" REMOVED Pushed Calvin's patch. --- sql/sql_class.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 97a227c8bb5..0b1de2c47fa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -655,8 +655,8 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, const char *proc_info= thd->proc_info; len= my_snprintf(header, sizeof(header), - "MySQL thread id %lu, query id %lu", - thd->thread_id, (ulong) thd->query_id); + "MySQL thread id %lu, OS thread handle 0x%lx, query id %lu", + thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id); str.length(0); str.append(header, len); From 669ff0370347ccf18622ba7f8dbe04e04c63795d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 15 Aug 2011 12:11:43 +0300 Subject: [PATCH 026/143] Bug #11766591 59733: Possible deadlock when buffered changes are to be discarded in buf_page_create() This bug turned out to be a false alarm, a bug in the UNIV_SYNC_DEBUG diagnostic code. Because of this, the patch was not backported to the built-in InnoDB in MySQL 5.1. Furthermore, there is no test case for InnoDB Plugin in MySQL 5.1, because the delete buffering in MySQL 5.5 makes triggering the failure much easier. When a freed page for which there exist orphaned buffered changes is allocated and reused for something else, buf_page_create() will discard the buffered changes by invoking ibuf_merge_or_delete_for_page(). This would violate the InnoDB latching order. Tweak the latching order as follows. Move SYNC_IBUF_MUTEX below SYNC_FSP_PAGE, where it logically belongs, and assign new latching levels for the ibuf->index->lock and the insert buffer B-tree pages: #define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */ #define SYNC_IBUF_INDEX_TREE 360 #define SYNC_IBUF_TREE_NODE_NEW 359 #define SYNC_IBUF_TREE_NODE 358 btr_block_get(), btr_page_get(): In UNIV_SYNC_DEBUG, add the parameter "index" for determining the appropriate latching order (SYNC_IBUF_TREE_NODE or SYNC_TREE_NODE). btr_page_alloc_for_ibuf(), btr_create(): Use SYNC_IBUF_TREE_NODE_NEW instead of SYNC_TREE_NODE_NEW for insert buffer pages. btr_cur_search_to_nth_level(), btr_pcur_restore_position_func(): Use SYNC_IBUF_TREE_NODE instead of SYNC_TREE_NODE for insert buffer pages. btr_search_guess_on_hash(): Assert that the index is not an insert buffer tree. dict_index_add_to_cache(): Use SYNC_IBUF_INDEX_TREE for the insert buffer tree (ibuf->index->lock). ibuf0ibuf.c: Use SYNC_IBUF_TREE_NODE or SYNC_IBUF_TREE_NODE_NEW for all B-tree pages. ibuf_merge_or_delete_for_page(): Assert that the user page is BUF_IO_READ fixed. Only in this way it is OK to latch it as SYNC_IBUF_TREE_NODE instead of the proper SYNC_TREE_NODE (which would violate the changed latching order). sync_thread_add_level(): Remove the special tweak for SYNC_IBUF_MUTEX. Add rules for the added latching levels. rb:591 approved by Jimmy Yang --- storage/innodb_plugin/ChangeLog | 9 ++ storage/innodb_plugin/btr/btr0btr.c | 100 ++++++++++++++-------- storage/innodb_plugin/btr/btr0cur.c | 36 ++++---- storage/innodb_plugin/btr/btr0pcur.c | 11 ++- storage/innodb_plugin/btr/btr0sea.c | 3 +- storage/innodb_plugin/dict/dict0crea.c | 4 +- storage/innodb_plugin/dict/dict0dict.c | 6 +- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 24 ++++-- storage/innodb_plugin/include/btr0btr.h | 34 ++++++-- storage/innodb_plugin/include/btr0btr.ic | 10 ++- storage/innodb_plugin/include/sync0sync.h | 9 +- storage/innodb_plugin/sync/sync0sync.c | 31 ++++--- 12 files changed, 181 insertions(+), 96 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f873f3a24bd..0b90b5729d5 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,12 @@ +2011-08-15 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, + dict/dict0crea.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c, + include/btr0btr.h, include/btr0btr.ic, include/sync0sync.h, + sync/sync0sync.c: + Fix Bug#11766591 59733: Possible deadlock when buffered changes + are to be discarded in buf_page_create() + 2011-08-08 The InnoDB Team * row/row0sel.c: diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index ac188c8c2fd..5e6724bbd54 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -690,7 +690,8 @@ btr_root_block_get( zip_size = dict_table_zip_size(index->table); root_page_no = dict_index_get_page(index); - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + index, mtr); ut_a((ibool)!!page_is_comp(buf_block_get_frame(block)) == dict_table_is_comp(index->table)); #ifdef UNIV_BTR_DEBUG @@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf( dict_table_zip_size(index->table), node_addr.page, RW_X_LATCH, mtr); new_page = buf_block_get_frame(new_block); - buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level(new_block, SYNC_IBUF_TREE_NODE_NEW); flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, @@ -1139,7 +1140,7 @@ btr_node_ptr_get_child( page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); return(btr_block_get(space, dict_table_zip_size(index->table), - page_no, RW_X_LATCH, mtr)); + page_no, RW_X_LATCH, index, mtr)); } /************************************************************//** @@ -1311,7 +1312,8 @@ btr_create( space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); - buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level( + ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(buf_block_get_page_no(ibuf_hdr_block) == IBUF_HEADER_PAGE_NO); @@ -1348,10 +1350,9 @@ btr_create( page_no = buf_block_get_page_no(block); frame = buf_block_get_frame(block); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - if (type & DICT_IBUF) { /* It is an insert buffer tree: initialize the free list */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); @@ -1359,6 +1360,8 @@ btr_create( } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ + buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + if (!fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { /* Not enough space for new segment, free root @@ -1430,7 +1433,8 @@ btr_free_but_not_root( leaf_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + root, space)); @@ -1452,7 +1456,8 @@ leaf_loop: top_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + root, space)); @@ -1478,13 +1483,13 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr) /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; fseg_header_t* header; - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, mtr); btr_search_drop_page_hash_index(block); @@ -2362,9 +2367,8 @@ btr_attach_half_pages( /* Update page links of the level */ if (prev_page_no != FIL_NULL) { - buf_block_t* prev_block = btr_block_get(space, zip_size, - prev_page_no, - RW_X_LATCH, mtr); + buf_block_t* prev_block = btr_block_get( + space, zip_size, prev_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(prev_block->frame) == page_is_comp(page)); ut_a(btr_page_get_next(prev_block->frame, mtr) @@ -2377,9 +2381,8 @@ btr_attach_half_pages( } if (next_page_no != FIL_NULL) { - buf_block_t* next_block = btr_block_get(space, zip_size, - next_page_no, - RW_X_LATCH, mtr); + buf_block_t* next_block = btr_block_get( + space, zip_size, next_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_block->frame) == page_is_comp(page)); ut_a(btr_page_get_prev(next_block->frame, mtr) @@ -2801,17 +2804,42 @@ func_exit: return(rec); } +#ifdef UNIV_SYNC_DEBUG +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,index,mtr) +#else /* UNIV_SYNC_DEBUG */ +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,mtr) +#endif /* UNIV_SYNC_DEBUG */ + /*************************************************************//** Removes a page from the level list of pages. */ -static +static __attribute__((nonnull)) void -btr_level_list_remove( -/*==================*/ - ulint space, /*!< in: space where removed */ - ulint zip_size,/*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - page_t* page, /*!< in: page to remove */ - mtr_t* mtr) /*!< in: mtr */ +btr_level_list_remove_func( +/*=======================*/ + ulint space, /*!< in: space where removed */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + page_t* page, /*!< in/out: page to remove */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree */ +#endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint prev_page_no; ulint next_page_no; @@ -2829,7 +2857,7 @@ btr_level_list_remove( if (prev_page_no != FIL_NULL) { buf_block_t* prev_block = btr_block_get(space, zip_size, prev_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* prev_page = buf_block_get_frame(prev_block); #ifdef UNIV_BTR_DEBUG @@ -2846,7 +2874,7 @@ btr_level_list_remove( if (next_page_no != FIL_NULL) { buf_block_t* next_block = btr_block_get(space, zip_size, next_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG @@ -3172,7 +3200,7 @@ btr_compress( if (is_left) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3181,7 +3209,7 @@ btr_compress( } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3270,7 +3298,7 @@ err_exit: btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); @@ -3327,7 +3355,7 @@ err_exit: #endif /* UNIV_BTR_DEBUG */ /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); /* Replace the address of the old child node (= page) with the address of the merge page to the right */ @@ -3519,7 +3547,7 @@ btr_discard_page( if (left_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3527,7 +3555,7 @@ btr_discard_page( #endif /* UNIV_BTR_DEBUG */ } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3562,7 +3590,7 @@ btr_discard_page( btr_node_ptr_delete(index, block, mtr); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); #ifdef UNIV_ZIP_DEBUG { page_zip_des_t* merge_page_zip @@ -4080,7 +4108,7 @@ loop: if (right_page_no != FIL_NULL) { const rec_t* right_rec; right_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); right_page = buf_block_get_frame(right_block); if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr) != page_get_page_no(page))) { @@ -4306,7 +4334,7 @@ node_ptr_fails: mtr_start(&mtr); block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); page = buf_block_get_frame(block); goto loop; diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index f378c477537..5cefa51bcd5 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -238,7 +238,8 @@ btr_cur_latch_leaves( case BTR_SEARCH_LEAF: case BTR_MODIFY_LEAF: mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH; - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -249,9 +250,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, left_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -261,8 +262,9 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -271,9 +273,9 @@ btr_cur_latch_leaves( right_page_no = btr_page_get_next(page, mtr); if (right_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - right_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, right_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -292,8 +294,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, + left_page_no, mode, cursor->index, mtr); cursor->left_block = get_block; #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) @@ -304,7 +307,8 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -572,7 +576,9 @@ retry_page_get: ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } ut_ad(0 == ut_dulint_cmp(index->id, @@ -630,8 +636,8 @@ retry_page_get: if (level > 0) { /* x-latch the page */ - page = btr_page_get(space, zip_size, - page_no, RW_X_LATCH, mtr); + page = btr_page_get(space, zip_size, page_no, + RW_X_LATCH, index, mtr); ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table)); } diff --git a/storage/innodb_plugin/btr/btr0pcur.c b/storage/innodb_plugin/btr/btr0pcur.c index 056896c7927..3bd2e9fd7d6 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 @@ -266,8 +266,10 @@ btr_pcur_restore_position_func( file, line, mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; - buf_block_dbg_add_level(btr_pcur_get_block(cursor), - SYNC_TREE_NODE); + buf_block_dbg_add_level( + btr_pcur_get_block(cursor), + dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); if (cursor->rel_pos == BTR_PCUR_ON) { #ifdef UNIV_DEBUG @@ -417,7 +419,8 @@ btr_pcur_move_to_next_page( ut_ad(next_page_no != FIL_NULL); next_block = btr_block_get(space, zip_size, next_page_no, - cursor->latch_mode, mtr); + cursor->latch_mode, + btr_pcur_get_btr_cur(cursor)->index, mtr); next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_page) == page_is_comp(page)); diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index cd0eadbb1b8..88442b7d4f0 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -832,6 +832,7 @@ btr_search_guess_on_hash( btr_pcur_t pcur; #endif ut_ad(index && info && tuple && cursor && mtr); + ut_ad(!dict_index_is_ibuf(index)); ut_ad((latch_mode == BTR_SEARCH_LEAF) || (latch_mode == BTR_MODIFY_LEAF)); diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 7d6cbc8c1c8..a57b2eca9e2 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.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 @@ -828,7 +828,7 @@ dict_truncate_index_tree( appropriate field in the SYS_INDEXES record: this mini-transaction marks the B-tree totally truncated */ - btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, NULL, mtr); btr_free_root(space, zip_size, root_page_no, mtr); create: diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index a8787bbda61..2d2262acf87 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.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 @@ -1661,7 +1661,9 @@ undo_size_ok: new_index->stat_n_leaf_pages = 1; new_index->page = page_no; - rw_lock_create(&new_index->lock, SYNC_INDEX_TREE); + rw_lock_create(&new_index->lock, + dict_index_is_ibuf(index) + ? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE); if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index 23981ac388e..effd7b9572b 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.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 @@ -356,7 +356,7 @@ ibuf_tree_root_get( block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); return(buf_block_get_frame(block)); } @@ -496,7 +496,7 @@ ibuf_init_at_db_start(void) block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); root = buf_block_get_frame(block); } @@ -1766,7 +1766,7 @@ ibuf_add_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); @@ -1897,8 +1897,7 @@ ibuf_remove_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); - + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); page = buf_block_get_frame(block); } @@ -2408,7 +2407,7 @@ ibuf_get_volume_buffered( block = buf_page_get( IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); prev_page = buf_block_get_frame(block); @@ -2482,7 +2481,7 @@ count_later: block = buf_page_get( IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); next_page = buf_block_get_frame(block); @@ -3248,6 +3247,7 @@ ibuf_merge_or_delete_for_page( ut_ad(!block || buf_block_get_space(block) == space); ut_ad(!block || buf_block_get_page_no(block) == page_no); ut_ad(!block || buf_block_get_zip_size(block) == zip_size); + ut_ad(!block || buf_block_get_io_fix(block) == BUF_IO_READ); if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE || trx_sys_hdr_page(space, page_no)) { @@ -3403,7 +3403,13 @@ loop: ut_a(success); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + /* This is a user page (secondary index leaf page), + but we pretend that it is a change buffer page in + order to obey the latching order. This should be OK, + because buffered changes are applied immediately while + the block is io-fixed. Other threads must not try to + latch an io-fixed block. */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); } /* Position pcur in the insert buffer at the first entry for this diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index 987de03b349..c0a038dd21d 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -188,26 +188,45 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ - mtr_t* mtr) /*!< in/out: mtr */ - __attribute__((nonnull)); +# ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +# endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr); /*!< in/out: mini-transaction */ +# ifdef UNIV_SYNC_DEBUG /** Gets a buffer page and declares its latching order level. @param space tablespace identifier @param zip_size compressed page size in bytes or 0 for uncompressed pages @param page_no page number @param mode latch mode +@param index index tree, may be NULL if not the insert buffer tree @param mtr mini-transaction handle @return the block descriptor */ -# define btr_block_get(space,zip_size,page_no,mode,mtr) \ - btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# define btr_block_get(space,zip_size,page_no,mode,index,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode, \ + __FILE__,__LINE__,index,mtr) +# else /* UNIV_SYNC_DEBUG */ /** Gets a buffer page and declares its latching order level. @param space tablespace identifier @param zip_size compressed page size in bytes or 0 for uncompressed pages @param page_no page number @param mode latch mode +@param idx index tree, may be NULL if not the insert buffer tree +@param mtr mini-transaction handle +@return the block descriptor */ +# define btr_block_get(space,zip_size,page_no,mode,idx,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# endif /* UNIV_SYNC_DEBUG */ +/** Gets a buffer page and declares its latching order level. +@param space tablespace identifier +@param zip_size compressed page size in bytes or 0 for uncompressed pages +@param page_no page number +@param mode latch mode +@param idx index tree, may be NULL if not the insert buffer tree @param mtr mini-transaction handle @return the uncompressed page frame */ -# define btr_page_get(space,zip_size,page_no,mode,mtr) \ - buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr)) +# define btr_page_get(space,zip_size,page_no,mode,idx,mtr) \ + buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr)) #endif /* !UNIV_HOTBACKUP */ /**************************************************************//** Gets the index id field of a page. @@ -333,8 +352,7 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr); /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr); /*!< in/out: mini-transaction */ /*************************************************************//** Makes tree one level higher by splitting the root, and inserts the tuple. It is assumed that mtr contains an x-latch on the tree. diff --git a/storage/innodb_plugin/include/btr0btr.ic b/storage/innodb_plugin/include/btr0btr.ic index 83eb3627abb..1837d091ccf 100644 --- a/storage/innodb_plugin/include/btr0btr.ic +++ b/storage/innodb_plugin/include/btr0btr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -48,6 +48,10 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +#endif /* UNIV_SYNC_DEBUG */ mtr_t* mtr) /*!< in/out: mtr */ { buf_block_t* block; @@ -57,7 +61,9 @@ btr_block_get_func( if (mode != RW_NO_LATCH) { - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, index != NULL && dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } return(block); diff --git a/storage/innodb_plugin/include/sync0sync.h b/storage/innodb_plugin/include/sync0sync.h index d9dcf91accb..f2013c202c1 100644 --- a/storage/innodb_plugin/include/sync0sync.h +++ b/storage/innodb_plugin/include/sync0sync.h @@ -448,10 +448,6 @@ or row lock! */ #define SYNC_DICT_HEADER 995 #define SYNC_IBUF_HEADER 914 #define SYNC_IBUF_PESS_INSERT_MUTEX 912 -#define SYNC_IBUF_MUTEX 910 /* ibuf mutex is really below - SYNC_FSP_PAGE: we assign a value this - high only to make the program to pass - the debug checks */ /*-------------------------------*/ #define SYNC_INDEX_TREE 900 #define SYNC_TREE_NODE_NEW 892 @@ -468,8 +464,11 @@ or row lock! */ #define SYNC_FSP 400 #define SYNC_FSP_PAGE 395 /*------------------------------------- Insert buffer headers */ -/*------------------------------------- ibuf_mutex */ +#define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */ /*------------------------------------- Insert buffer tree */ +#define SYNC_IBUF_INDEX_TREE 360 +#define SYNC_IBUF_TREE_NODE_NEW 359 +#define SYNC_IBUF_TREE_NODE 358 #define SYNC_IBUF_BITMAP_MUTEX 351 #define SYNC_IBUF_BITMAP 350 /*------------------------------------- MySQL query cache mutex */ diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 59498386fda..1b97e1f11f3 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1173,6 +1173,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: + case SYNC_IBUF_MUTEX: if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" @@ -1236,21 +1237,27 @@ sync_thread_add_level( || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: - ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) - || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)); break; case SYNC_INDEX_TREE: - if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP)) { - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, - TRUE)); - } else { - ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, - TRUE)); - } + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; - case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); + case SYNC_IBUF_TREE_NODE: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_INDEX_TREE) + || sync_thread_levels_g(array, SYNC_IBUF_TREE_NODE - 1, + TRUE)); + break; + case SYNC_IBUF_TREE_NODE_NEW: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + break; + case SYNC_IBUF_INDEX_TREE: + if (sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g( + array, SYNC_FSP_PAGE - 1, TRUE)); + } else { + ut_a(sync_thread_levels_g( + array, SYNC_IBUF_TREE_NODE - 1, TRUE)); + } break; case SYNC_IBUF_PESS_INSERT_MUTEX: ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); From 888b8793a256040ab9b7e008c52936da75a3d116 Mon Sep 17 00:00:00 2001 From: Daniel Fischer Date: Mon, 15 Aug 2011 12:10:08 +0200 Subject: [PATCH 027/143] Source plugin library files list from cmake-generated file in RPM builds --- cmake/plugin.cmake | 4 ++++ support-files/mysql.spec.sh | 28 +++++----------------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index 6f534568a2d..e3e3c584d47 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -196,6 +196,10 @@ MACRO(MYSQL_ADD_PLUGIN) # Install dynamic library MYSQL_INSTALL_TARGETS(${target} DESTINATION ${INSTALL_PLUGINDIR} COMPONENT Server) INSTALL_DEBUG_TARGET(${target} DESTINATION ${INSTALL_PLUGINDIR}/debug) + # Add installed files to list for RPMs + FILE(APPEND ${CMAKE_BINARY_DIR}/support-files/plugins.files + "%attr(755, root, root) %{_prefix}/${INSTALL_PLUGINDIR}/${ARG_MODULE_OUTPUT_NAME}.so\n" + "%attr(755, root, root) %{_prefix}/${INSTALL_PLUGINDIR}/debug/${ARG_MODULE_OUTPUT_NAME}.so\n") # For internal testing in PB2, append collections files IF(DEFINED ENV{PB2WORKDIR}) PLUGIN_APPEND_COLLECTIONS(${plugin}) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 69eecbb3d01..9bbf846e706 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -944,7 +944,7 @@ echo "=====" >> $STATUS_HISTORY # Files section ############################################################################## -%files -n MySQL-server%{product_suffix} +%files -n MySQL-server%{product_suffix} -f release/support-files/plugins.files %defattr(-,root,root,0755) %if %{defined license_files_server} @@ -1015,28 +1015,6 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug %attr(755, root, root) %{_sbindir}/rcmysql -%attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so -%attr(755, root, root) %{_libdir}/mysql/plugin/libdaemon_example.so -%attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so -%attr(755, root, root) %{_libdir}/mysql/plugin/semisync_master.so -%attr(755, root, root) %{_libdir}/mysql/plugin/semisync_slave.so -%attr(755, root, root) %{_libdir}/mysql/plugin/auth.so -%attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so -%attr(755, root, root) %{_libdir}/mysql/plugin/auth_test_plugin.so -%attr(755, root, root) %{_libdir}/mysql/plugin/qa_auth_client.so -%attr(755, root, root) %{_libdir}/mysql/plugin/qa_auth_interface.so -%attr(755, root, root) %{_libdir}/mysql/plugin/qa_auth_server.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/adt_null.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/libdaemon_example.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/mypluglib.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/semisync_master.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/semisync_slave.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth_socket.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth_test_plugin.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/qa_auth_client.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/qa_auth_interface.so -%attr(755, root, root) %{_libdir}/mysql/plugin/debug/qa_auth_server.so %if %{WITH_TCMALLOC} %attr(755, root, root) %{_libdir}/mysql/%{malloc_lib_target} @@ -1131,6 +1109,10 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Fri Aug 12 2011 Daniel Fischer + +- Source plugin library files list from cmake-generated file. + * Thu Jul 21 2011 Sunanda Menon - Fix bug#12561297: Added the MySQL embedded binary From 6e5bbf513810448e84872069065a0561e0d70a93 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 15 Aug 2011 18:29:38 +0400 Subject: [PATCH 028/143] Cherry-picking WL#5710 from mysql-5.5 to mysql-5.5.16-release. Original revision id: # revno: 3489 [merge] # revision-id: tatjana.nuernberg@oracle.com-20110811120945-c6x9a5d2du8s9oj2 # parent: tatjana.nuernberg@oracle.com-20110811112736-so8r813hs8dmf7nr # parent: chuck.bell@oracle.com-20110810183949-2s9uxcuoux2p668e # committer: Tatjana Azundris Nuernberg # branch nick: 55-9 # timestamp: Thu 2011-08-11 13:09:45 +0100 # message: # auto-merge This merge revision also has a patch for Bug 12664445, which has been also taken to 5.5.16. --- client/CMakeLists.txt | 5 +- client/mysql_plugin.c | 1192 +++++++++++++++++ include/my_global.h | 4 + .../include/daemon_example_bad_format.ini | 8 + .../include/daemon_example_bad_soname.ini | 9 + mysql-test/include/plugin.defs | 1 + mysql-test/mysql-test-run.pl | 3 + mysql-test/r/mysql_plugin.result | 110 ++ mysql-test/suite/sys_vars/r/all_vars.result | 6 - .../r/innodb_file_format_check_basic.result | 125 +- .../r/innodb_file_format_max_basic.result | 65 + .../r/innodb_rollback_segments_basic.result | 64 + .../r/innodb_stats_method_basic.result | 83 ++ .../t/innodb_file_format_check_basic.test | 112 +- .../t/innodb_file_format_max_basic.test | 60 + .../t/innodb_rollback_segments_basic.test | 58 + .../sys_vars/t/innodb_stats_method_basic.test | 72 + mysql-test/t/mysql_plugin-master.opt | 1 + mysql-test/t/mysql_plugin.test | 318 +++++ plugin/daemon_example/CMakeLists.txt | 2 + plugin/daemon_example/daemon_example.ini | 9 + support-files/mysql.spec.sh | 6 + 22 files changed, 2218 insertions(+), 95 deletions(-) create mode 100644 client/mysql_plugin.c create mode 100644 mysql-test/include/daemon_example_bad_format.ini create mode 100644 mysql-test/include/daemon_example_bad_soname.ini create mode 100644 mysql-test/r/mysql_plugin.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test create mode 100644 mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test create mode 100644 mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test create mode 100644 mysql-test/t/mysql_plugin-master.opt create mode 100644 mysql-test/t/mysql_plugin.test create mode 100644 plugin/daemon_example/daemon_example.ini diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 80c5bbd1c9f..c5bda7d8a35 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -54,6 +54,9 @@ ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) MYSQL_ADD_EXECUTABLE(mysqlshow mysqlshow.c) TARGET_LINK_LIBRARIES(mysqlshow mysqlclient) +MYSQL_ADD_EXECUTABLE(mysql_plugin mysql_plugin.c) +TARGET_LINK_LIBRARIES(mysql_plugin mysqlclient) + MYSQL_ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc) TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient) @@ -69,7 +72,7 @@ IF(WIN32) MYSQL_ADD_EXECUTABLE(echo echo.c) ENDIF(WIN32) -SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap +SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap mysql_plugin PROPERTIES HAS_CXX TRUE) ADD_DEFINITIONS(-DHAVE_DLOPEN) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c new file mode 100644 index 00000000000..6679fa9ca6f --- /dev/null +++ b/client/mysql_plugin.c @@ -0,0 +1,1192 @@ +/* + 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 +*/ + +#include +#include +#include +#include +#include +#include +#include + + +#define SHOW_VERSION "1.0.0" +#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \ + my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \ + } while(0) + +/* Global variables. */ +static uint my_end_arg= 0; +static uint opt_verbose=0; +static uint opt_no_defaults= 0; +static uint opt_print_defaults= 0; +static char *opt_datadir=0, *opt_basedir=0, + *opt_plugin_dir=0, *opt_plugin_ini=0, + *opt_mysqld=0, *opt_my_print_defaults=0; +static char bootstrap[FN_REFLEN]; + + +/* plugin struct */ +struct st_plugin +{ + const char *name; /* plugin name */ + const char *so_name; /* plugin so (library) name */ + const char *components[16]; /* components to load */ +} plugin_data; + + +/* Options */ +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"basedir", 'b', "The basedir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"datadir", 'd', "The datadir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-dir", 'p', "The plugin dir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-ini", 'i', "Read plugin information from configuration file " + "specified instead of from /.ini.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-defaults", 'n', "Do not read values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"print-defaults", 'P', "Show default values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"my-print-defaults", 'f', "Path to my_print_defaults executable. " + "Example: /source/temp11/extra", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', + "More verbose output; you can use this multiple times to get even more " + "verbose output.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +/* Methods */ +static int process_options(int argc, char *argv[], char *operation); +static int check_access(); +static int find_tool(const char *tool_name, char *tool_path); +static int find_plugin(char *tp_path); +static int build_bootstrap_file(char *operation, char *bootstrap); +static int dump_bootstrap_file(char *bootstrap_file); +static int bootstrap_server(char *server_path, char *bootstrap_file); + + +int main(int argc,char *argv[]) +{ + int error= 0; + char tp_path[FN_REFLEN]; + char server_path[FN_REFLEN]; + char operation[16]; + + MY_INIT(argv[0]); + plugin_data.name= 0; // initialize name + + /* + The following operations comprise the method for enabling or disabling + a plugin. We begin by processing the command options then check the + directories specified for --datadir, --basedir, --plugin-dir, and + --plugin-ini (if specified). If the directories are Ok, we then look + for the mysqld executable and the plugin soname. Finally, we build a + bootstrap command file for use in bootstraping the server. + + If any step fails, the method issues an error message and the tool exits. + + 1) Parse, execute, and verify command options. + 2) Check access to directories. + 3) Look for mysqld executable. + 4) Look for the plugin. + 5) Build a bootstrap file with commands to enable or disable plugin. + + */ + if ((error= process_options(argc, argv, operation)) || + (error= check_access()) || + (error= find_tool("mysqld" FN_EXEEXT, server_path)) || + (error= find_plugin(tp_path)) || + (error= build_bootstrap_file(operation, bootstrap))) + goto exit; + + /* Dump the bootstrap file if --verbose specified. */ + if (opt_verbose && ((error= dump_bootstrap_file(bootstrap)))) + goto exit; + + /* Start the server in bootstrap mode and execute bootstrap commands */ + error= bootstrap_server(server_path, bootstrap); + +exit: + /* Remove file */ + my_delete(bootstrap, MYF(0)); + if (opt_verbose && error == 0) + { + printf("# Operation succeeded.\n"); + } + + my_end(my_end_arg); + exit(error ? 1 : 0); + return 0; /* No compiler warnings */ +} + + +/** + Get a temporary file name. + + @param[out] filename The file name of the temporary file + @param[in] ext An extension for the file (optional) + + @retval int error = 1, success = 0 +*/ + +static int make_tempfile(char *filename, const char *ext) +{ + int fd= 0; + + if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY, + MYF(MY_WME))) < 0) + { + fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n", + fd); + return 1; + } + my_close(fd, MYF(0)); + return 0; +} + + +/** + Get the value of an option from a string read from my_print_defaults output. + + @param[in] line The line (string) read from the file + @param[in] item The option to search for (e.g. --datadir) + + @returns NULL if not found, string containing value if found +*/ + +static char *get_value(char *line, const char *item) +{ + char *destination= 0; + int item_len= (int)strlen(item); + int line_len = (int)strlen(line); + + if ((strncasecmp(line, item, item_len) == 0)) + { + int start= 0; + char *s= 0; + + s = line + item_len + 1; + destination= my_strndup(s, line_len - start, MYF(MY_FAE)); + destination[line_len - item_len - 2]= 0; + } + return destination; +} + + +/** + Run a command in a shell. + + This function will attempt to execute the command specified by using the + popen() method to open a shell and execute the command passed and store the + output in a result file. If the --verbose option was specified, it will open + the result file and print the contents to stdout. + + @param[in] cmd The command to execute. + @param[in] mode The mode for popen() (e.g. "r", "w", "rw") + + @return int error code or 0 for success. +*/ + +static int run_command(char* cmd, const char *mode) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, mode))) + return -1; + + if (opt_verbose) + { + while (fgets(buf, sizeof(buf), res_file)) + { + fprintf(stdout, "%s", buf); + } + } + error= pclose(res_file); + return error; +} + + +#ifdef __WIN__ +/** + Check to see if there are spaces in a path. + + @param[in] path The Windows path to examine. + + @retval int spaces found = 1, no spaces = 0 +*/ +static int has_spaces(const char *path) +{ + if (strchr(path, ' ') != NULL) + return 1; + return 0; +} + + +/** + Convert a Unix path to a Windows path. + + @param[in] path The Windows path to examine. + + @returns string containing path with / changed to \\ +*/ +static char *convert_path(const char *argument) +{ + /* Convert / to \\ to make Windows paths */ + char *winfilename= my_strdup(argument, MYF(MY_FAE)); + char *pos, *end; + int length= strlen(argument); + + for (pos= winfilename, end= pos+length ; pos < end ; pos++) + { + if (*pos == '/') + { + *pos= '\\'; + } + } + return winfilename; +} + + +/** + Add quotes if the path has spaces in it. + + @param[in] path The Windows path to examine. + + @returns string containing excaped quotes if spaces found in path +*/ +static char *add_quotes(const char *path) +{ + char windows_cmd_friendly[FN_REFLEN]; + + if (has_spaces(path)) + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "\"%s\"", path); + else + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "%s", path); + return my_strdup(windows_cmd_friendly, MYF(MY_FAE)); +} +#endif + + +/** + Get the default values from the my.cnf file. + + This method gets the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + + These values are used if the user has not specified a value. + + @retval int error = 1, success = 0 +*/ + +static int get_default_values() +{ + char tool_path[FN_REFLEN]; + char defaults_cmd[FN_REFLEN]; + char defaults_file[FN_REFLEN]; + char line[FN_REFLEN]; + int error= 0; + int ret= 0; + FILE *file= 0; + + bzero(tool_path, FN_REFLEN); + if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) + goto exit; + else + { + if ((error= make_tempfile(defaults_file, "txt"))) + goto exit; + +#ifdef __WIN__ + { + char *format_str= 0; + + if (has_spaces(tool_path) || has_spaces(defaults_file)) + format_str = "\"%s mysqld > %s\""; + else + format_str = "%s mysqld > %s"; + + snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, + add_quotes(tool_path), add_quotes(defaults_file)); + if (opt_verbose) + { + printf("# my_print_defaults found: %s\n", tool_path); + } + } +#else + snprintf(defaults_cmd, sizeof(defaults_cmd), + "%s mysqld > %s", tool_path, defaults_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", defaults_cmd); + } + error= run_command(defaults_cmd, "r"); + if (error) + { + fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n", + ret); + goto exit; + } + /* Now open the file and read the defaults we want. */ + file= fopen(defaults_file, "r"); + while (fgets(line, FN_REFLEN, file) != NULL) + { + char *value= 0; + + if ((opt_datadir == 0) && ((value= get_value(line, "--datadir")))) + { + opt_datadir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_basedir == 0) && ((value= get_value(line, "--basedir")))) + { + opt_basedir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")))) + { + opt_plugin_dir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini")))) + { + opt_plugin_ini= my_strdup(value, MYF(MY_FAE)); + } + } + } +exit: + if (file) + { + fclose(file); + /* Remove file */ + my_delete(defaults_file, MYF(0)); + } + return error; +} + + +/** + Print usage. +*/ + +static void usage(void) +{ + PRINT_VERSION; + puts("Copyright (c) 2011, Oracle and/or its affiliates. " + "All rights reserved.\n"); + puts("Enable or disable plugins."); + printf("\nUsage: %s [options] ENABLE|DISABLE\n\nOptions:\n", + my_progname); + my_print_help(my_long_options); + puts("\n"); +} + + +/** + Print the default values as read from the my.cnf file. + + This method displays the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + +*/ + +static void print_default_values(void) +{ + printf("%s would have been started with the following arguments:\n", + my_progname); + get_default_values(); + if (opt_datadir) + { + printf("--datadir=%s ", opt_datadir); + } + if (opt_basedir) + { + printf("--basedir=%s ", opt_basedir); + } + if (opt_plugin_dir) + { + printf("--plugin_dir=%s ", opt_plugin_dir); + } + if (opt_plugin_ini) + { + printf("--plugin_ini=%s ", opt_plugin_ini); + } + if (opt_mysqld) + { + printf("--mysqld=%s ", opt_mysqld); + } + if (opt_my_print_defaults) + { + printf("--my_print_defaults=%s ", opt_my_print_defaults); + } + printf("\n"); +} + + +/** + Process the arguments and identify an option and store its value. + + @param[in] optid The single character shortcut for the argument. + @param[in] my_option Structure of legal options. + @param[in] argument The argument value to process. +*/ + +static my_bool +get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch(optid) { + case 'n': + opt_no_defaults++; + break; + case 'P': + opt_print_defaults++; + print_default_values(); + break; + case 'v': + opt_verbose++; + break; + case 'V': + PRINT_VERSION; + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + case 'd': + opt_datadir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'b': + opt_basedir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'p': + opt_plugin_dir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'i': + opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); + break; + case 'm': + opt_mysqld= my_strdup(argument, MYF(MY_FAE)); + break; + case 'f': + opt_my_print_defaults= my_strdup(argument, MYF(MY_FAE)); + break; + } + return 0; +} + + +/** + Check to see if a file exists. + + @param[in] filename File to locate. + + @retval int file not found = 1, file found = 0 +*/ + +static int file_exists(char * filename) +{ + MY_STAT stat_arg; + + if (!my_stat(filename, &stat_arg, MYF(0))) + { + return 0; + } + return 1; +} + + +/** + Search a specific path and sub directory for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[in] subdir The sub directory to search. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_dir(const char * base_path, const char *tool_name, + const char *subdir, char *tool_path) +{ + char new_path[FN_REFLEN]; + char source_path[FN_REFLEN]; + + strcpy(source_path, base_path); + strcat(source_path, subdir); + fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME); + if (file_exists(new_path)) + { + strcpy(tool_path, new_path); + return 1; + } + return 0; +} + + +/** + Search known common paths and sub directories for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_paths(const char *base_path, const char *tool_name, + char *tool_path) +{ + int i= 0; + + static const char *paths[]= { + "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/", + "/mysql/", "/sql/", + }; + for (i = 0 ; i < (int)array_elements(paths); i++) + { + if (search_dir(base_path, tool_name, paths[i], tool_path)) + { + return 1; + } + } + return 0; +} + + +/** + Read the plugin ini file. + + This function attempts to read the plugin config file from the plugin_dir + path saving the data in the the st_plugin structure. If the file is not + found or the file cannot be read, an error is generated. + + @retval int error = 1, success = 0 +*/ + +static int load_plugin_data(char *plugin_name, char *config_file) +{ + FILE *file_ptr; + char path[FN_REFLEN]; + char line[1024]; + char *reason= 0; + char *res; + int i= -1; + + if (opt_plugin_ini == 0) + { + fn_format(path, config_file, opt_plugin_dir, "", MYF(0)); + opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); + } + if (!file_exists(opt_plugin_ini)) + { + reason= (char *)"File does not exist."; + goto error; + } + + file_ptr= fopen(opt_plugin_ini, "r"); + if (file_ptr == NULL) + { + reason= (char *)"Cannot open file."; + goto error; + } + + /* save name */ + plugin_data.name= my_strdup(plugin_name, MYF(MY_WME)); + + /* Read plugin components */ + while (i < 16) + { + res= fgets(line, sizeof(line), file_ptr); + /* strip /n */ + if (line[strlen(line)-1] == '\n') + { + line[strlen(line)-1]= '\0'; + } + if (res == NULL) + { + if (i < 1) + { + reason= (char *)"Bad format in plugin configuration file."; + fclose(file_ptr); + goto error; + } + break; + } + if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines + { + continue; + } + if (i == -1) // if first pass, read this line as so_name + { + /* Add proper file extension for soname */ + strcat(line, FN_SOEXT); + /* save so_name */ + plugin_data.so_name= my_strdup(line, MYF(MY_WME|MY_ZEROFILL)); + i++; + } + else + { + if (strlen(line) > 0) + { + plugin_data.components[i]= my_strdup(line, MYF(MY_WME)); + i++; + } + else + { + plugin_data.components[i]= NULL; + } + } + } + + fclose(file_ptr); + return 0; + +error: + fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n", + plugin_name, reason); + return 1; +} + + +/** + Check the options for validity. + + This function checks the arguments for validity issuing the appropriate + error message if arguments are missing or invalid. On success, @operation + is set to either "ENABLE" or "DISABLE". + + @param[in] argc The number of arguments. + @param[in] argv The arguments. + @param[out] operation The operation chosen (enable|disable) + + @retval int error = 1, success = 0 +*/ + +static int check_options(int argc, char **argv, char *operation) +{ + int i= 0; // loop counter + int num_found= 0; // number of options found (shortcut loop) + char config_file[FN_REFLEN]; // configuration file name + char plugin_name[FN_REFLEN]; // plugin name + + /* Form prefix strings for the options. */ + const char *basedir_prefix = "--basedir="; + int basedir_len= strlen(basedir_prefix); + const char *datadir_prefix = "--datadir="; + int datadir_len= strlen(datadir_prefix); + const char *plugin_dir_prefix = "--plugin_dir="; + int plugin_dir_len= strlen(plugin_dir_prefix); + + strcpy(plugin_name, ""); + for (i = 0; i < argc && num_found < 5; i++) + { + + if (!argv[i]) + { + continue; + } + if ((strcasecmp(argv[i], "ENABLE") == 0) || + (strcasecmp(argv[i], "DISABLE") == 0)) + { + strcpy(operation, argv[i]); + num_found++; + } + else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) && + !opt_basedir) + { + opt_basedir= my_strndup(argv[i]+basedir_len, + strlen(argv[i])-basedir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) && + !opt_datadir) + { + opt_datadir= my_strndup(argv[i]+datadir_len, + strlen(argv[i])-datadir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) && + !opt_plugin_dir) + { + opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len, + strlen(argv[i])-plugin_dir_len, MYF(MY_FAE)); + num_found++; + } + /* read the plugin config file and check for match against argument */ + else + { + strcpy(plugin_name, argv[i]); + strcpy(config_file, argv[i]); + strcat(config_file, ".ini"); + } + } + + if (!opt_basedir) + { + fprintf(stderr, "ERROR: Missing --basedir option.\n"); + return 1; + } + + if (!opt_datadir) + { + fprintf(stderr, "ERROR: Missing --datadir option.\n"); + return 1; + } + + if (!opt_plugin_dir) + { + fprintf(stderr, "ERROR: Missing --plugin_dir option.\n"); + return 1; + } + /* If a plugin was specified, read the config file. */ + else if (strlen(plugin_name) > 0) + { + if (load_plugin_data(plugin_name, config_file)) + { + return 1; + } + if (strcasecmp(plugin_data.name, plugin_name) != 0) + { + fprintf(stderr, "ERROR: plugin name requested does not match config " + "file data.\n"); + return 1; + } + } + else + { + fprintf(stderr, "ERROR: No plugin specified.\n"); + return 1; + } + + if ((strlen(operation) == 0)) + { + fprintf(stderr, "ERROR: missing operation. Please specify either " + "' ENABLE' or ' DISABLE'.\n"); + return 1; + } + + return 0; +} + + +/** + Parse, execute, and verify command options. + + This method handles all of the option processing including the optional + features for displaying data (--print-defaults, --help ,etc.) that do not + result in an attempt to ENABLE or DISABLE of a plugin. + + @param[in] arc Count of arguments + @param[in] argv Array of arguments + @param[out] operation Operation (ENABLE or DISABLE) + + @retval int error = 1, success = 0, exit program = -1 +*/ + +static int process_options(int argc, char *argv[], char *operation) +{ + int error= 0; + int i= 0; + + /* Parse and execute command-line options */ + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) + goto exit; + + /* If the print defaults option used, exit. */ + if (opt_print_defaults) + { + error= -1; + goto exit; + } + + /* Add a trailing directory separator if not present */ + if (opt_basedir) + { + i= (int)strlength(opt_basedir); + if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) +#ifdef __WIN__ + if (opt_basedir[i-1] != '/') + strcat(opt_basedir, "//"); +#else + strcat(opt_basedir, FN_DIRSEP); +#endif + } + + /* + If the user did not specify the option to skip loading defaults from a + config file and the required options are not present or there was an error + generated when the defaults were read from the file, exit. + */ + if (!opt_no_defaults && ((error= get_default_values()))) + { + error= -1; + goto exit; + } + + /* + Check to ensure required options are present and validate the operation. + Note: this method also validates the plugin specified by attempting to + read a configuration file named .ini from the --plugin-dir + or --plugin-ini location if the --plugin-ini option presented. + */ + strcpy(operation, ""); + if ((error = check_options(argc, argv, operation))) + { + goto exit; + } + + if (opt_verbose) + { + printf("# basedir = %s\n", opt_basedir); + printf("# plugin_dir = %s\n", opt_plugin_dir); + printf("# datadir = %s\n", opt_datadir); + printf("# plugin_ini = %s\n", opt_plugin_ini); + } + +exit: + return error; +} + + +/** + Check access + + This method checks to ensure all of the directories (opt_basedir, + opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by + the user. + + @retval int error = 1, success = 0 +*/ + +static int check_access() +{ + int error= 0; + + if ((error= my_access(opt_basedir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n", + opt_basedir); + goto exit; + } + if ((error= my_access(opt_plugin_dir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n", + opt_plugin_dir); + goto exit; + } + if ((error= my_access(opt_datadir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n", + opt_datadir); + goto exit; + } + if ((error= my_access(opt_plugin_ini, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", + opt_plugin_ini); + goto exit; + } + if ((error= my_access(opt_mysqld, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n", + opt_mysqld); + goto exit; + } + if ((error= my_access(opt_my_print_defaults, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n", + opt_my_print_defaults); + goto exit; + } + +exit: + return error; +} + + +/** + Locate the tool and form tool path. + + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int find_tool(const char *tool_name, char *tool_path) +{ + int i= 0; + + const char *paths[]= { + opt_basedir, opt_mysqld, opt_my_print_defaults, "/usr", + "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug", + "/extra/release", "/bin", "/usr/bin", "/mysql/bin" + }; + for (i= 0; i < (int)array_elements(paths); i++) + { + if (paths[i] && (search_paths(paths[i], tool_name, tool_path))) + goto found; + } + fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name); + return 1; +found: + if (opt_verbose) + printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path); + return 0; +} + + +/** + Find the plugin library. + + This function attempts to use the @c plugin_dir option passed on the + command line to locate the plugin. + + @param[out] tp_path The actual path to plugin with FN_SOEXT applied. + + @retval int error = 1, success = 0 +*/ + +static int find_plugin(char *tp_path) +{ + /* Check for existance of plugin */ + fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0)); + if (!file_exists(tp_path)) + { + fprintf(stderr, "ERROR: The plugin library is missing or in a different" + " location.\n"); + return 1; + } + else if (opt_verbose) + { + printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path); + } + return 0; +} + + +/** + Build the boostrap file. + + Create a new file and populate it with SQL commands to ENABLE or DISABLE + the plugin via INSERT and DELETE operations on the mysql.plugin table. + + param[in] operation The type of operation (ENABLE or DISABLE) + param[out] bootstrap A FILE* pointer + + @retval int error = 1, success = 0 +*/ + +static int build_bootstrap_file(char *operation, char *bootstrap) +{ + int error= 0; + FILE *file= 0; + + /* + Perform plugin operation : ENABLE or DISABLE + + The following creates a temporary bootstrap file and populates it with + the appropriate SQL commands for the operation. For ENABLE, INSERT + statements are created. For DISABLE, DELETE statements are created. The + values for these statements are derived from the plugin_data read from the + .ini configuration file. Once the file is built, a call to + mysqld is made in read only, bootstrap modes to read the SQL statements + and execute them. + */ + if ((error= make_tempfile(bootstrap, "sql"))) + { + /* Fail if we cannot create a temporary file for the bootstrap commands. */ + fprintf(stderr, "ERROR: Cannot create bootstrap file.\n"); + goto exit; + } + if ((file= fopen(bootstrap, "w+")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n"); + error= 1; + goto exit; + } + if (strcasecmp(operation, "enable") == 0) + { + int i= 0; + fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES "); + for (i= 0; i < (int)array_elements(plugin_data.components); i++) + { + /* stop when we read the end of the symbol list - marked with NULL */ + if (plugin_data.components[i] == NULL) + { + break; + } + if (i > 0) + { + fprintf(file, ", "); + } + fprintf(file, "('%s','%s')", + plugin_data.components[i], plugin_data.so_name); + } + fprintf(file, ";\n"); + if (opt_verbose) + { + printf("# Enabling %s...\n", plugin_data.name); + } + } + else + { + fprintf(file, + "DELETE FROM mysql.plugin WHERE name = '%s';", plugin_data.name); + if (opt_verbose) + { + printf("# Disabling %s...\n", plugin_data.name); + } + } + +exit: + fclose(file); + return error; +} + + +/** + Dump bootstrap file. + + Read the contents of the bootstrap file and print it out. + + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int dump_bootstrap_file(char *bootstrap_file) +{ + char *ret= 0; + int error= 0; + char query_str[512]; + FILE *file= 0; + + if ((file= fopen(bootstrap_file, "r")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n"); + error= 1; + goto exit; + } + ret= fgets(query_str, 512, file); + if (ret == 0) + { + fprintf(stderr, "ERROR: Cannot read bootstrap file.\n"); + error= 1; + goto exit; + } + printf("# Query: %s", query_str); + +exit: + if (file) + { + fclose(file); + } + return error; +} + + +/** + Bootstrap the server + + Create a command line sequence to launch mysqld in bootstrap mode. This + will allow mysqld to launch a minimal server instance to read and + execute SQL commands from a file piped in (the boostrap file). We use + the --no-defaults option to skip reading values from the config file. + + The bootstrap mode skips loading of plugins and many other subsystems. + This allows the mysql_plugin tool to insert the correct rows into the + mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once + the server is launched in normal mode, the plugin will be loaded + (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the + (sometimes) complicated LOAD PLUGIN commands. + + @param[in] server_path Path to server executable + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int bootstrap_server(char *server_path, char *bootstrap_file) +{ + char bootstrap_cmd[FN_REFLEN]; + int error= 0; + int ret= 0; + +#ifdef __WIN__ + char *format_str= 0; + char *verbose_str= ""; + + if (opt_verbose) + strcat(verbose_str, "--console"); + if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || + has_spaces(bootstrap_file)) + format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; + else + format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s"; + + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str, + add_quotes(convert_path(server_path)), verbose_str, + add_quotes(opt_datadir), add_quotes(opt_basedir), + add_quotes(bootstrap_file)); +#else + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), + "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" + " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", bootstrap_cmd); + } + error= run_command(bootstrap_cmd, "r"); + if (error) + fprintf(stderr, + "ERROR: Unexpected result from bootstrap. Error code: %d.\n", + ret); + + return error; +} diff --git a/include/my_global.h b/include/my_global.h index f465d031b62..924c83cd951 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -603,6 +603,8 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '\\' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/\\" /* Valid directory separators */ +#define FN_EXEEXT ".exe" +#define FN_SOEXT ".dll" #define FN_ROOTDIR "\\" #define FN_DEVCHAR ':' #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ @@ -611,6 +613,8 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '/' #define FN_LIBCHAR2 '/' #define FN_DIRSEP "/" /* Valid directory separators */ +#define FN_EXEEXT "" +#define FN_SOEXT ".so" #define FN_ROOTDIR "/" #endif diff --git a/mysql-test/include/daemon_example_bad_format.ini b/mysql-test/include/daemon_example_bad_format.ini new file mode 100644 index 00000000000..8f880ef0ba0 --- /dev/null +++ b/mysql-test/include/daemon_example_bad_format.ini @@ -0,0 +1,8 @@ +# +# Plugin configuration file. Place the following on a separate line: +# +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin +# +libdaemon_example diff --git a/mysql-test/include/daemon_example_bad_soname.ini b/mysql-test/include/daemon_example_bad_soname.ini new file mode 100644 index 00000000000..5f42b5a6214 --- /dev/null +++ b/mysql-test/include/daemon_example_bad_soname.ini @@ -0,0 +1,9 @@ +# +# Plugin configuration file. Place the following on a separate line: +# +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin +# +libdaemon_BADNAME +daemon_BADNAME diff --git a/mysql-test/include/plugin.defs b/mysql-test/include/plugin.defs index e07c603c8e5..6fbe4f68328 100644 --- a/mysql-test/include/plugin.defs +++ b/mysql-test/include/plugin.defs @@ -39,3 +39,4 @@ ha_archive storage/archive ARCHIVE_PLUGIN ha_blackhole storage/blackhole BLACKHOLE_PLUGIN ha_federated storage/federated FEDERATED_PLUGIN mypluglib plugin/fulltext SIMPLE_PARSER +libdaemon_example plugin/daemon_example DAEMONEXAMPLE diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 82d17a21f89..ec0ca74b1d1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -168,6 +168,7 @@ my $opt_suites; our $opt_verbose= 0; # Verbose output, enable with --verbose our $exe_mysql; +our $exe_mysql_plugin; our $exe_mysqladmin; our $exe_mysqltest; our $exe_libtool; @@ -1950,6 +1951,7 @@ sub executable_setup () { # Look for the client binaries $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + $exe_mysql_plugin= mtr_exe_exists("$path_client_bindir/mysql_plugin"); $exe_mysql_embedded= mtr_exe_maybe_exists("$basedir/libmysqld/examples/mysql_embedded"); @@ -2357,6 +2359,7 @@ sub environment_setup { $ENV{'MYSQLADMIN'}= native_path($exe_mysqladmin); $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); $ENV{'EXE_MYSQL'}= $exe_mysql; + $ENV{'MYSQL_PLUGIN'}= $exe_mysql_plugin; $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded; # ---------------------------------------------------- diff --git a/mysql-test/r/mysql_plugin.result b/mysql-test/r/mysql_plugin.result new file mode 100644 index 00000000000..949f3748236 --- /dev/null +++ b/mysql-test/r/mysql_plugin.result @@ -0,0 +1,110 @@ +# +# Ensure the plugin isn't loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +# +# Enable the plugin... +# +# +# Ensure the plugin is now loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +daemon_example libdaemon_example.so +# +# Disable the plugin... +# +# +# Ensure the plugin isn't loaded. +# +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; +name dl +# +# Attempt to load non-existant plugin +# +ERROR: Cannot read plugin config file NOT_THERE_AT_ALL. File does not exist. +# +# Attempt to use non-existant plugin.ini file +# +ERROR: Cannot read plugin config file daemon_example. File does not exist. +# +# Attempt to omit the plugin +# +ERROR: No plugin specified. +# +# Attempt to omit DISABLE|ENABLE +# +ERROR: missing operation. Please specify either ' ENABLE' or ' DISABLE'. +# +# Attempt to use bad paths - datadir +# +ERROR: Cannot access datadir at '/data_not_there/'. +# +# Attempt to use bad paths - basedir +# +ERROR: Cannot access basedir at '/basedir_not_there/'. +# +# Attempt to use bad paths - plugin_dir +# +ERROR: Cannot read plugin config file daemon_example. File does not exist. +# +# Attempt to use bad paths - mysqld +# +ERROR: Cannot access mysqld path '/mysqld_not_there/'. +# +# Attempt to use bad paths - my_print_defaults +# +ERROR: Cannot access my-print-defaults path '/my_print_defaults_not_there/'. +# +# Missing library +# +ERROR: The plugin library is missing or in a different location. +# +# Bad format for config file +# +ERROR: Cannot read plugin config file daemon_example. Bad format in plugin configuration file. +# +# Missing base_dir option +# +ERROR: Missing --basedir option. +# +# Missing data_dir option +# +ERROR: Missing --datadir option. +# +# Missing plugin_dir option +# +ERROR: Missing --plugin_dir option. +# +# Show the help. +# +mysql_plugin Ver V.V.VV Distrib XX.XX.XX +Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + +Enable or disable plugins. + +Usage: mysql_plugin [options] ENABLE|DISABLE + +Options: + -?, --help Display this help and exit. + -b, --basedir=name The basedir for the server. + -d, --datadir=name The datadir for the server. + -p, --plugin-dir=name + The plugin dir for the server. + -i, --plugin-ini=name + Read plugin information from configuration file specified + instead of from /.ini. + -n, --no-defaults Do not read values from configuration file. + -P, --print-defaults + Show default values from configuration file. + -m, --mysqld=name Path to mysqld executable. Example: /sbin/temp1/mysql/bin + -f, --my-print-defaults=name + Path to my_print_defaults executable. Example: + /source/temp11/extra + -v, --verbose More verbose output; you can use this multiple times to + get even more verbose output. + -V, --version Output version information and exit. + + +mysql_plugin Ver V.V.VV Distrib XX.XX.XX diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 3cee368853f..715ad9e2c15 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,13 +11,7 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: -INNODB_ROLLBACK_SEGMENTS -INNODB_STATS_METHOD -INNODB_FILE_FORMAT_MAX INNODB_LARGE_PREFIX -INNODB_ROLLBACK_SEGMENTS -INNODB_STATS_METHOD -INNODB_FILE_FORMAT_MAX INNODB_LARGE_PREFIX drop table t1; drop table t2; diff --git a/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result index c59e1b802f4..9167585f1d6 100644 --- a/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_file_format_check_basic.result @@ -1,59 +1,80 @@ -SET @start_global_value = @@global.innodb_file_format_max; +SET @start_global_value = @@global.innodb_file_format_check; SELECT @start_global_value; @start_global_value -Antelope -Valid values are 'Antelope' and 'Barracuda' -select @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); -@@global.innodb_file_format_max in ('Antelope', 'Barracuda') 1 -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope -select @@session.innodb_file_format_max; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable -show global variables like 'innodb_file_format_max'; +Valid values are 'ON' and 'OFF' +SELECT @@global.innodb_file_format_check in (0, 1); +@@global.innodb_file_format_check in (0, 1) +1 +SELECT @@global.innodb_file_format_check; +@@global.innodb_file_format_check +1 +SELECT @@session.innodb_file_format_check; +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +SHOW global variables LIKE 'innodb_file_format_check'; Variable_name Value -innodb_file_format_max Antelope -show session variables like 'innodb_file_format_max'; +innodb_file_format_check ON +SHOW session variables LIKE 'innodb_file_format_check'; Variable_name Value -innodb_file_format_max Antelope -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; +innodb_file_format_check ON +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_check'; VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; +INNODB_FILE_FORMAT_CHECK ON +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_check'; VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -set global innodb_file_format_max='Antelope'; -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Antelope -set @@global.innodb_file_format_max='Barracuda'; -select @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Barracuda -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Barracuda -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -VARIABLE_NAME VARIABLE_VALUE -INNODB_FILE_FORMAT_MAX Barracuda -set session innodb_file_format_max='Salmon'; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL -set @@session.innodb_file_format_max='Salmon'; -ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL -set global innodb_file_format_max=1.1; -ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' -set global innodb_file_format_max=1e1; -ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' -set global innodb_file_format_max='Salmon'; -ERROR 42000: Variable 'innodb_file_format_max' can't be set to the value of 'Salmon' -SET @@global.innodb_file_format_max = @start_global_value; -SELECT @@global.innodb_file_format_max; -@@global.innodb_file_format_max -Antelope +INNODB_FILE_FORMAT_CHECK ON +SET @@global.innodb_file_format_check='Off'; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check=1; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check=0; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET @@global.innodb_file_format_check='On'; +ERROR HY000: Variable 'innodb_file_format_check' is a read only variable +Expected error 'Read only variable' +SET session innodb_large_prefix='OFF'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_stats_on_metadata='ON'; +ERROR HY000: Variable 'innodb_stats_on_metadata' is a GLOBAL variable and should be set with SET GLOBAL +SELECT IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +COUNT(@@GLOBAL.innodb_file_format_check) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT @@innodb_file_format_check = @@GLOBAL.innodb_file_format_check; +@@innodb_file_format_check = @@GLOBAL.innodb_file_format_check +1 +1 Expected +SELECT COUNT(@@innodb_file_format_check); +COUNT(@@innodb_file_format_check) +1 +1 Expected +SELECT COUNT(@@local.innodb_file_format_check); +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_file_format_check); +ERROR HY000: Variable 'innodb_file_format_check' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +COUNT(@@GLOBAL.innodb_file_format_check) +1 +1 Expected +SELECT innodb_file_format_check = @@SESSION.innodb_file_format_check; +ERROR 42S22: Unknown column 'innodb_file_format_check' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result new file mode 100644 index 00000000000..32b2262c091 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_file_format_max_basic.result @@ -0,0 +1,65 @@ +SET @start_global_value = @@global.innodb_file_format_max; +SELECT @start_global_value; +@start_global_value +Antelope +Valid values are 'Antelope' and 'Barracuda' +SELECT @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); +@@global.innodb_file_format_max in ('Antelope', 'Barracuda') +1 +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope +SELECT @@session.innodb_file_format_max; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable +SHOW global variables LIKE 'innodb_file_format_max'; +Variable_name Value +innodb_file_format_max Antelope +SHOW session variables LIKE 'innodb_file_format_max'; +Variable_name Value +innodb_file_format_max Antelope +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SET global innodb_file_format_max='Antelope'; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Antelope +SET @@global.innodb_file_format_max='Barracuda'; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Barracuda +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Barracuda +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_FILE_FORMAT_MAX Barracuda +SET session innodb_file_format_max='Salmon'; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_file_format_max='Salmon'; +ERROR HY000: Variable 'innodb_file_format_max' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_file_format_max=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' +SET global innodb_file_format_max=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_file_format_max' +SET global innodb_file_format_max='Salmon'; +ERROR 42000: Variable 'innodb_file_format_max' can't be set to the value of 'Salmon' +SET @@global.innodb_file_format_max = @start_global_value; +SELECT @@global.innodb_file_format_max; +@@global.innodb_file_format_max +Antelope diff --git a/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result b/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result new file mode 100644 index 00000000000..a8d392eee38 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_rollback_segments_basic.result @@ -0,0 +1,64 @@ +SET @start_global_value = @@global.innodb_rollback_segments; +SELECT @start_global_value; +@start_global_value +128 +Valid values are zero or above +SELECT @@global.innodb_rollback_segments >=0; +@@global.innodb_rollback_segments >=0 +1 +SELECT @@global.innodb_rollback_segments <=128; +@@global.innodb_rollback_segments <=128 +1 +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +128 +SELECT @@session.innodb_rollback_segments; +ERROR HY000: Variable 'innodb_rollback_segments' is a GLOBAL variable +SHOW global variables LIKE 'innodb_rollback_segments'; +Variable_name Value +innodb_rollback_segments 128 +SHOW session variables LIKE 'innodb_rollback_segments'; +Variable_name Value +innodb_rollback_segments 128 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 128 +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 128 +SET global innodb_rollback_segments=100; +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +100 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 100 +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 100 +SET session innodb_rollback_segments=1; +ERROR HY000: Variable 'innodb_rollback_segments' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_rollback_segments=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments="foo"; +ERROR 42000: Incorrect argument type to variable 'innodb_rollback_segments' +SET global innodb_rollback_segments=-7; +Warnings: +Warning 1292 Truncated incorrect innodb_rollback_segments value: '-7' +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +1 +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_ROLLBACK_SEGMENTS 1 +SET @@global.innodb_rollback_segments = @start_global_value; +SELECT @@global.innodb_rollback_segments; +@@global.innodb_rollback_segments +128 diff --git a/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result b/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result new file mode 100644 index 00000000000..6599ca9edb6 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_stats_method_basic.result @@ -0,0 +1,83 @@ +SET @start_global_value = @@global.innodb_stats_method; +SELECT @start_global_value; +@start_global_value +nulls_equal +Valid values are 'nulls_equal', 'nulls_unequal', 'nulls_ignored' +SELECT @@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored'); +@@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored') +1 +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal +SELECT @@session.innodb_stats_method; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable +SHOW global variables LIKE 'innodb_stats_method'; +Variable_name Value +innodb_stats_method nulls_equal +SHOW session variables LIKE 'innodb_stats_method'; +Variable_name Value +innodb_stats_method nulls_equal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SET global innodb_stats_method='nulls_equal'; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_equal +SET @@global.innodb_stats_method='nulls_unequal'; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_unequal +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_unequal +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_unequal +SET global innodb_stats_method=2; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_ignored +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_ignored +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_STATS_METHOD nulls_ignored +SET session innodb_stats_method='nulls_equal'; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable and should be set with SET GLOBAL +SET @@session.innodb_stats_method='nulls_ignored'; +ERROR HY000: Variable 'innodb_stats_method' is a GLOBAL variable and should be set with SET GLOBAL +SET global innodb_stats_method=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_stats_method' +SET global innodb_stats_method=4; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of '4' +SET global innodb_stats_method=-2; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of '-2' +SET global innodb_stats_method=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_stats_method' +SET global innodb_stats_method='some'; +ERROR 42000: Variable 'innodb_stats_method' can't be set to the value of 'some' +SET @@global.innodb_stats_method = @start_global_value; +SELECT @@global.innodb_stats_method; +@@global.innodb_stats_method +nulls_equal diff --git a/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test index cbf25af2442..f9f61b9380c 100644 --- a/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_file_format_check_basic.test @@ -1,55 +1,95 @@ - - -# 2010-01-25 - Added # +# 2011-08-02 - Added +# + --source include/not_embedded.inc --source include/have_innodb.inc -SET @start_global_value = @@global.innodb_file_format_max; +SET @start_global_value = @@global.innodb_file_format_check; SELECT @start_global_value; # # exists as global only # ---echo Valid values are 'Antelope' and 'Barracuda' -select @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); -select @@global.innodb_file_format_max; +--echo Valid values are 'ON' and 'OFF' +SELECT @@global.innodb_file_format_check in (0, 1); +SELECT @@global.innodb_file_format_check; + --error ER_INCORRECT_GLOBAL_LOCAL_VAR -select @@session.innodb_file_format_max; -show global variables like 'innodb_file_format_max'; -show session variables like 'innodb_file_format_max'; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; +SELECT @@session.innodb_file_format_check; +SHOW global variables LIKE 'innodb_file_format_check'; +SHOW session variables LIKE 'innodb_file_format_check'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_check'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_check'; # -# show that it's writable +# show that it's read only # -set global innodb_file_format_max='Antelope'; -select @@global.innodb_file_format_max; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; -set @@global.innodb_file_format_max='Barracuda'; -select @@global.innodb_file_format_max; -select * from information_schema.global_variables where variable_name='innodb_file_format_max'; -select * from information_schema.session_variables where variable_name='innodb_file_format_max'; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check='Off'; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check=1; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check=0; +--echo Expected error 'Read only variable' + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@global.innodb_file_format_check='On'; +--echo Expected error 'Read only variable' + --error ER_GLOBAL_VARIABLE -set session innodb_file_format_max='Salmon'; +SET session innodb_large_prefix='OFF'; --error ER_GLOBAL_VARIABLE -set @@session.innodb_file_format_max='Salmon'; +SET @@session.innodb_stats_on_metadata='ON'; # -# incorrect types -# ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_file_format_max=1.1; ---error ER_WRONG_TYPE_FOR_VAR -set global innodb_file_format_max=1e1; ---error ER_WRONG_VALUE_FOR_VAR -set global innodb_file_format_max='Salmon'; - -# -# Cleanup +# Check if the value in GLOBAL Table matches value in variable # -SET @@global.innodb_file_format_max = @start_global_value; -SELECT @@global.innodb_file_format_max; +SELECT IF(@@GLOBAL.innodb_file_format_check, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_file_format_check'; +--echo 1 Expected + +# +# Check if accessing variable with and without GLOBAL point to same variable +# +SELECT @@innodb_file_format_check = @@GLOBAL.innodb_file_format_check; +--echo 1 Expected + +# +# Check if innodb_doublewrite can be accessed with and without @@ sign +# + +SELECT COUNT(@@innodb_file_format_check); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_file_format_check); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_file_format_check); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_file_format_check); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_file_format_check = @@SESSION.innodb_file_format_check; +--echo Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test new file mode 100644 index 00000000000..c2cb4cb47bb --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_file_format_max_basic.test @@ -0,0 +1,60 @@ +# +# 2011-08-02 - Added +# +--source include/not_embedded.inc +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_file_format_max; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'Antelope' and 'Barracuda' +SELECT @@global.innodb_file_format_max in ('Antelope', 'Barracuda'); +SELECT @@global.innodb_file_format_max; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_file_format_max; +SHOW global variables LIKE 'innodb_file_format_max'; +SHOW session variables LIKE 'innodb_file_format_max'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; + +# +# show that it's writable +# +SET global innodb_file_format_max='Antelope'; +SELECT @@global.innodb_file_format_max; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +SET @@global.innodb_file_format_max='Barracuda'; +SELECT @@global.innodb_file_format_max; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_file_format_max'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_file_format_max'; +--error ER_GLOBAL_VARIABLE +SET session innodb_file_format_max='Salmon'; +--error ER_GLOBAL_VARIABLE +SET @@session.innodb_file_format_max='Salmon'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_file_format_max=1.1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_file_format_max=1e1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_file_format_max='Salmon'; + +# +# Cleanup +# + +SET @@global.innodb_file_format_max = @start_global_value; +SELECT @@global.innodb_file_format_max; diff --git a/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test b/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test new file mode 100644 index 00000000000..9f0b70a528f --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_rollback_segments_basic.test @@ -0,0 +1,58 @@ +# +# 2011-08-01 Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_rollback_segments; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are zero or above +SELECT @@global.innodb_rollback_segments >=0; +SELECT @@global.innodb_rollback_segments <=128; +SELECT @@global.innodb_rollback_segments; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_rollback_segments; +SHOW global variables LIKE 'innodb_rollback_segments'; +SHOW session variables LIKE 'innodb_rollback_segments'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; + +# +# show that it's writable +# +SET global innodb_rollback_segments=100; +SELECT @@global.innodb_rollback_segments; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_rollback_segments'; +--error ER_GLOBAL_VARIABLE +SET session innodb_rollback_segments=1; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments=1.1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments=1e1; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_rollback_segments="foo"; +SET global innodb_rollback_segments=-7; +SELECT @@global.innodb_rollback_segments; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_rollback_segments'; + +# +# cleanup +# + +SET @@global.innodb_rollback_segments = @start_global_value; +SELECT @@global.innodb_rollback_segments; diff --git a/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test b/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test new file mode 100644 index 00000000000..f01574c3683 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_stats_method_basic.test @@ -0,0 +1,72 @@ +# +# 2011-08-05 - Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_stats_method; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'nulls_equal', 'nulls_unequal', 'nulls_ignored' +SELECT @@global.innodb_stats_method in ('nulls_equal', 'nulls_unequal', +'nulls_ignored'); +SELECT @@global.innodb_stats_method; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_stats_method; +SHOW global variables LIKE 'innodb_stats_method'; +SHOW session variables LIKE 'innodb_stats_method'; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; + +# +# show that it's writable +# +SET global innodb_stats_method='nulls_equal'; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +SET @@global.innodb_stats_method='nulls_unequal'; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; +SET global innodb_stats_method=2; +SELECT @@global.innodb_stats_method; +SELECT * FROM information_schema.global_variables +WHERE variable_name='innodb_stats_method'; +SELECT * FROM information_schema.session_variables +WHERE variable_name='innodb_stats_method'; + +--error ER_GLOBAL_VARIABLE +SET session innodb_stats_method='nulls_equal'; +--error ER_GLOBAL_VARIABLE +SET @@session.innodb_stats_method='nulls_ignored'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_stats_method=1.1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method=4; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method=-2; +--error ER_WRONG_TYPE_FOR_VAR +SET global innodb_stats_method=1e1; +--error ER_WRONG_VALUE_FOR_VAR +SET global innodb_stats_method='some'; + +# +# Cleanup +# + +SET @@global.innodb_stats_method = @start_global_value; +SELECT @@global.innodb_stats_method; diff --git a/mysql-test/t/mysql_plugin-master.opt b/mysql-test/t/mysql_plugin-master.opt new file mode 100644 index 00000000000..061ca907902 --- /dev/null +++ b/mysql-test/t/mysql_plugin-master.opt @@ -0,0 +1 @@ +--plugin-dir=$DAEMONEXAMPLE_DIR diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test new file mode 100644 index 00000000000..9e71db1a451 --- /dev/null +++ b/mysql-test/t/mysql_plugin.test @@ -0,0 +1,318 @@ +# +# Test mysql_plugin tool +# +# This test contains test cases for testing the mysql_plugin client with +# the daemon_example plugin. Test cases include tests for: +# +# - successful enable/disable +# - incorrect paths +# - missing paths/options +# +# Implementation Notes +# +# The mysql_plugin tool now accepts --mysqld the path to mysqld server. The +# mysqld path is extracted from MYSQLD_BOOTSTRAP_CMD line. We also extract +# the path of MYSQLD_BASEDIR (where mysql exists) and use it for the errmsg +# file. The directories differ between Windows and Unix but the Perl script +# included below will pick as per platform. +# +# The test is also designed to issue the --skip directive if the location of +# the mysqld, my_print_defaults, or daemon_example.ini files cannot be found. +# + +--source include/not_embedded.inc + +# Add the datadir, basedir, plugin_dir to the bootstrap command +let $MYSQLD_DATADIR= `select @@datadir`; +let $MYSQL_BASEDIR= `select @@basedir`; +let $MYSQL_ERRMSG_BASEDIR=`select @@lc_messages_dir`; +let $PLUGIN_DIR=`select @@plugin_dir`; + +--disable_abort_on_error + +# Perl script to extract the location of the basedir from environment +# variables. This is needed to ensure the test will run on the PB machines +# designed to test release as well as debug builds. It also checks for the +# location of the my_print_defaults and daemon_example.ini files. + +perl; +use File::Basename; + my ($mysqld)= split " ", $ENV{MYSQLD_BOOTSTRAP_CMD}; + my $mysqld_basedir=dirname($mysqld); + my $my_print_defaults= $ENV{MYSQL_MY_PRINT_DEFAULTS}; + my $my_print_defaults_basedir=dirname($my_print_defaults); + my $daemonexample_ini= "$ENV{DAEMONEXAMPLE_DIR}/daemon_example.ini"; + my $plugindir_ini= "$ENV{PLUGIN_DIR}/daemon_example.ini"; + my $notfound= ""; + open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/mysqld.inc") or die; + print FILE "let \$MYSQLD= $mysqld;\n"; + print FILE "let \$MYSQLD_BASEDIR= $mysqld_basedir;\n"; + print FILE "let \$MYSQL_MY_PRINT_DEFAULTS_BASEDIR= $my_print_defaults_basedir;\n"; + if ((!-e $daemonexample_ini) || (!-r $daemonexample_ini)) + { + print FILE "let \$DAEMONEXAMPLE_DIR= $not_found;\n"; + } + if ((!-e $plugindir_ini) || (!-r $plugindir_ini)) + { + print FILE "let \$PLUGIN_DIR= $not_found;\n"; + } + close FILE; +EOF + + +source $MYSQL_TMP_DIR/mysqld.inc; +remove_file $MYSQL_TMP_DIR/mysqld.inc; + +# The mysql_plugin tool expects a directory structure like in the installed +# mysql version, so errmsg.sys will be copied to "basedir/share", we create +# and remove this structure. + +--mkdir $MYSQLD_BASEDIR/share +--mkdir $MYSQLD_BASEDIR/share/mysql +--copy_file $MYSQL_ERRMSG_BASEDIR/english/errmsg.sys $MYSQLD_BASEDIR/share/errmsg.sys +--copy_file $MYSQL_ERRMSG_BASEDIR/english/errmsg.sys $MYSQLD_BASEDIR/share/mysql/errmsg.sys + +# The mysql_plugin tool now accepts --my-print-defaults which points to the +# executable my_print_defaults.exe we can get this path from the variable +# $MYSQL_MY_PRINT_DEFAULTS. + +# Check for my_print_defaults location. Skip if not found. +if ($MYSQL_MY_PRINT_DEFAULTS_BASEDIR == '') +{ + --skip Test requires known location of my_print_defaults executable. +} + +# Check for mysqld location. Skip if not found. +if ($MYSQLD == '') +{ + --skip Test requires known location of mysqld executable. +} + +# Check for daemon_example.ini location. Skip if not found in either +# the plugin_dir path or the daemon_example_dir path. +if ($PLUGIN_DIR == '') +{ + if ($DAEMONEXAMPLE_DIR == '') + { + --skip Test requires known location of daemon_example.ini file. + } + let $PLUGIN_DIR = $DAEMONEXAMPLE_DIR; +} + +# Build client command for reuse. + +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; + +--echo # +--echo # Ensure the plugin isn't loaded. +--echo # +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +--echo # +--echo # Enable the plugin... +--echo # +let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +# +# Enable the plugin +# +--exec $MYSQL_PLUGIN_CMD ENABLE daemon_example + +# +# Ensure enabling an enabled plugin doesn't fail +--exec $MYSQL_PLUGIN_CMD ENABLE daemon_example + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo # +--echo # Ensure the plugin is now loaded. +--echo # +--replace_regex /\.dll/.so/ +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +--echo # +--echo # Disable the plugin... +--echo # +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +# +# Disable the plugin +# +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +--echo # +--echo # Ensure the plugin isn't loaded. +--echo # +SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name; + +# +# Stop the server for error conditions +# +let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file +--write_file $expect_file +wait +EOF +--shutdown_server 10 +--source include/wait_until_disconnected.inc + +--echo # +--echo # Attempt to load non-existant plugin +--echo # +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE NOT_THERE_AT_ALL 2>&1 + +--echo # +--echo # Attempt to use non-existant plugin.ini file +--echo # +--error 1,2,7,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1 + +--echo # +--echo # Attempt to omit the plugin +--echo # +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE 2>&1 + +--echo # +--echo # Attempt to omit DISABLE|ENABLE +--echo # +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - datadir +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - basedir +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - plugin_dir +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=/plugin_not_there/ --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - mysqld +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=/mysqld_not_there/ --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Attempt to use bad paths - my_print_defaults +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=/my_print_defaults_not_there/; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + + +--echo # +--echo # Missing library +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_soname.ini --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Bad format for config file +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --plugin-ini=$MYSQL_TEST_DIR/include/daemon_example_bad_format.ini --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing base_dir option +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,139,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing data_dir option +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --basedir=$MYSQL_BASEDIR --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,139,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Missing plugin_dir option +--echo # +let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQL_BASEDIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +--error 1,2,139,256 +--exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 + +--echo # +--echo # Show the help. +--echo # +replace_result $MYSQL_PLUGIN mysql_plugin; +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--exec $MYSQL_PLUGIN --help + +replace_result $MYSQL_PLUGIN mysql_plugin; +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--exec $MYSQL_PLUGIN --version + +# +# Restart the server +# +--append_file $expect_file +restart +EOF +--enable_reconnect +--source include/wait_until_connected_again.inc + +# +# Cleanup +# MTR will remove this file later, but this might be too late. +--error 0,1 +--remove_file $expect_file + +# Cleanup the share folder in the binary path. +--remove_file $MYSQLD_BASEDIR/share/errmsg.sys +--rmdir $MYSQLD_BASEDIR/share/mysql +--rmdir $MYSQLD_BASEDIR/share + +--enable_abort_on_error diff --git a/plugin/daemon_example/CMakeLists.txt b/plugin/daemon_example/CMakeLists.txt index 60aa00687ba..1623c3025d7 100644 --- a/plugin/daemon_example/CMakeLists.txt +++ b/plugin/daemon_example/CMakeLists.txt @@ -15,3 +15,5 @@ MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc MODULE_ONLY MODULE_OUTPUT_NAME "libdaemon_example") + +INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR}) diff --git a/plugin/daemon_example/daemon_example.ini b/plugin/daemon_example/daemon_example.ini new file mode 100644 index 00000000000..7c6d4d1456e --- /dev/null +++ b/plugin/daemon_example/daemon_example.ini @@ -0,0 +1,9 @@ +# +# Plugin configuration file. Place the following on a separate line: +# +# library binary file name (without .so or .dll) +# component_name +# [component_name] - additional components in plugin +# +libdaemon_example +daemon_example diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 9bbf846e706..b32a7dd836c 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1000,6 +1000,7 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/mysql_setpermission %attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql %attr(755, root, root) %{_bindir}/mysql_upgrade +%attr(755, root, root) %{_bindir}/mysql_plugin %attr(755, root, root) %{_bindir}/mysql_zap %attr(755, root, root) %{_bindir}/mysqlbug %attr(755, root, root) %{_bindir}/mysqld_multi @@ -1015,6 +1016,7 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug %attr(755, root, root) %{_sbindir}/rcmysql +%attr(755, root, root) %{_libdir}/mysql/plugin/daemon_example.ini %if %{WITH_TCMALLOC} %attr(755, root, root) %{_libdir}/mysql/%{malloc_lib_target} @@ -1113,6 +1115,10 @@ echo "=====" >> $STATUS_HISTORY - Source plugin library files list from cmake-generated file. +* Mon Jul 25 2011 Chuck Bell + +- Added the mysql_plugin client - enables or disables plugins. + * Thu Jul 21 2011 Sunanda Menon - Fix bug#12561297: Added the MySQL embedded binary From 457cbab0d6e3b952a3a94b0dd04a38bb4644c4cd Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 15 Aug 2011 18:31:45 +0400 Subject: [PATCH 029/143] Cherry-picking a patch from Bug 12828477 from mysql-5.5 to mysql-5.5.16-release. Original revision: # revision-id: dmitry.lenev@oracle.com-20110811155849-feyt3h7tj48padiu # parent: tatjana.nuernberg@oracle.com-20110811120945-c6x9a5d2du8s9oj2 # committer: Dmitry Lenev # branch nick: mysql-5.5-12828477 # timestamp: Thu 2011-08-11 19:58:49 +0400 # message: # Fix for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD # FOR CERTAIN QUERIES TO INFORMATION_SCHEMA". # # The problem was that metadata locking subsystem introduced # too much overhead for queries to I_S which were processed by # opening only .FRM or .TRG files and had to scanned a lot of # tables (e.g. SELECT COUNT(*) FROM I_S.TRIGGERS was affected). # The same effect was not observed for similar queries which # performed full-blown table open in order to fill I_S table. # # The problem stemmed from the fact that in case when I_S # implementation opened only .FRM or .TRG file for each table # processed it didn't release metadata lock it has acquired on # the table after finishing its processing. As result, list # of acquired metadata locks were growing until the end of # statement. Since acquisition of each new lock required # search in the list of already acquired locks performance # degraded. # # The same effect is not observed when I_S implementation # performs full-blown table open for each table being # processed, as in the latter cases metadata lock on the # table is released right after table processing. # # This fix addressed the problem by ensuring that I_S # implementation releases metadata lock after processing # the table in both cases of full-blown table open and in # case when only .FRM or .TRG file is read. --- mysql-test/r/information_schema.result | 114 ++++++++++++++++ mysql-test/t/information_schema.test | 182 ++++++++++++++++++++++++- sql/sql_show.cc | 33 ++++- 3 files changed, 322 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 1418af5b813..88a56edbb5c 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1849,5 +1849,119 @@ unlock tables; drop table t1; drop view v1; # +# Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR +# CERTAIN QUERIES TO INFORMATION_SCHEMA". +# +# Check that metadata locks which are acquired during the process +# of opening tables/.FRMs/.TRG files while filling I_S table are +# not kept to the end of statement. Keeping the locks has caused +# performance problems in cases when big number of tables (.FRMs +# or .TRG files) were scanned as cost of new lock acquisition has +# increased linearly. +drop database if exists mysqltest; +create database mysqltest; +use mysqltest; +create table t0 (i int); +create table t1 (j int); +create table t2 (k int); +# +# Test that we don't keep locks in case when we to fill +# I_S table we perform full-blown table open. +# +# Acquire lock on 't2' so upcoming RENAME is +# blocked. +lock tables t2 read; +# +# Switching to connection 'con12828477_1'. +# +# The below RENAME should wait on 't2' while +# keeping X lock on 't1'. +rename table t1 to t3, t2 to t1, t3 to t2; +# +# Switching to connection 'con12828477_2'. +# +# Wait while the above RENAME is blocked. +# Issue query to I_S which will open 't0' and get +# blocked on 't1' because of RENAME. +select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'; +# +# Switching to connection 'con12828477_3'. +# +# Wait while the above SELECT is blocked. +# +# Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; +# +# Switching to connection 'default'. +# +# +# Unblock the first RENAME. +unlock tables; +# +# Switching to connection 'con12828477_1'. +# +# Reap the first RENAME +# +# Switching to connection 'con12828477_2'. +# +# Reap SELECT to I_S. +table_name auto_increment +t0 NULL +t1 NULL +t2 NULL +# +# Switching to connection 'default'. +# +# +# Now test that we don't keep locks in case when we to fill +# I_S table we read .FRM or .TRG file only (this was the case +# for which problem existed). +# +rename table t4 to t0; +# Acquire lock on 't2' so upcoming RENAME is +# blocked. +lock tables t2 read; +# +# Switching to connection 'con12828477_1'. +# +# The below RENAME should wait on 't2' while +# keeping X lock on 't1'. +rename table t1 to t3, t2 to t1, t3 to t2; +# +# Switching to connection 'con12828477_2'. +# +# Wait while the above RENAME is blocked. +# Issue query to I_S which will open 't0' and get +# blocked on 't1' because of RENAME. +select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'; +# +# Switching to connection 'con12828477_3'. +# +# Wait while the above SELECT is blocked. +# +# Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; +# +# Switching to connection 'default'. +# +# +# Unblock the first RENAME. +unlock tables; +# +# Switching to connection 'con12828477_1'. +# +# Reap the first RENAME +# +# Switching to connection 'con12828477_2'. +# +# Reap SELECT to I_S. +event_object_table trigger_name +# +# Switching to connection 'default'. +# +# +# Clean-up. +drop database mysqltest; +# # End of 5.5 tests # diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 589bb898d6a..e6dc989bdb9 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1543,8 +1543,6 @@ DROP TABLE t1, information_schema.tables; LOCK TABLES t1 READ, information_schema.tables READ; DROP TABLE t1; -# Wait till all disconnects are completed ---source include/wait_until_count_sessions.inc # # Bug #43834 Assertion in Natural_join_column::db_name() on an I_S query @@ -1608,6 +1606,186 @@ drop table t1; drop view v1; +--echo # +--echo # Test for bug #12828477 - "MDL SUBSYSTEM CREATES BIG OVERHEAD FOR +--echo # CERTAIN QUERIES TO INFORMATION_SCHEMA". +--echo # +--echo # Check that metadata locks which are acquired during the process +--echo # of opening tables/.FRMs/.TRG files while filling I_S table are +--echo # not kept to the end of statement. Keeping the locks has caused +--echo # performance problems in cases when big number of tables (.FRMs +--echo # or .TRG files) were scanned as cost of new lock acquisition has +--echo # increased linearly. +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +create database mysqltest; +use mysqltest; +create table t0 (i int); +create table t1 (j int); +create table t2 (k int); + +--echo # +--echo # Test that we don't keep locks in case when we to fill +--echo # I_S table we perform full-blown table open. +--echo # + +--echo # Acquire lock on 't2' so upcoming RENAME is +--echo # blocked. +lock tables t2 read; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connect (con12828477_1, localhost, root,,mysqltest); +--echo # The below RENAME should wait on 't2' while +--echo # keeping X lock on 't1'. +--send rename table t1 to t3, t2 to t1, t3 to t2 + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connect (con12828477_2, localhost, root,,mysqltest); +--echo # Wait while the above RENAME is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t3, t2 to t1, t3 to t2"; +--source include/wait_condition.inc + +--echo # Issue query to I_S which will open 't0' and get +--echo # blocked on 't1' because of RENAME. +--send select table_name, auto_increment from information_schema.tables where table_schema='mysqltest' + +--echo # +--echo # Switching to connection 'con12828477_3'. +--echo # +connect (con12828477_3, localhost, root,,mysqltest); +--echo # Wait while the above SELECT is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select table_name, auto_increment from information_schema.tables where table_schema='mysqltest'"; +--source include/wait_condition.inc + +--echo # +--echo # Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +--echo # +--echo # Unblock the first RENAME. +unlock tables; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # Reap the first RENAME +--reap + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Reap SELECT to I_S. +--reap + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; + +--echo # +--echo # Now test that we don't keep locks in case when we to fill +--echo # I_S table we read .FRM or .TRG file only (this was the case +--echo # for which problem existed). +--echo # + +rename table t4 to t0; +--echo # Acquire lock on 't2' so upcoming RENAME is +--echo # blocked. +lock tables t2 read; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # The below RENAME should wait on 't2' while +--echo # keeping X lock on 't1'. +--send rename table t1 to t3, t2 to t1, t3 to t2 + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Wait while the above RENAME is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "rename table t1 to t3, t2 to t1, t3 to t2"; +--source include/wait_condition.inc + +--echo # Issue query to I_S which will open 't0' and get +--echo # blocked on 't1' because of RENAME. +--send select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest' + +--echo # +--echo # Switching to connection 'con12828477_3'. +--echo # +connection con12828477_3; +--echo # Wait while the above SELECT is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "select event_object_table, trigger_name from information_schema.triggers where event_object_schema='mysqltest'"; +--source include/wait_condition.inc + +--echo # +--echo # Check that it holds no lock on 't0' so it can be renamed. +rename table t0 to t4; + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +--echo # +--echo # Unblock the first RENAME. +unlock tables; + +--echo # +--echo # Switching to connection 'con12828477_1'. +--echo # +connection con12828477_1; +--echo # Reap the first RENAME +--reap + +--echo # +--echo # Switching to connection 'con12828477_2'. +--echo # +connection con12828477_2; +--echo # Reap SELECT to I_S. +--reap + +--echo # +--echo # Switching to connection 'default'. +--echo # +connection default; +disconnect con12828477_1; +disconnect con12828477_2; +disconnect con12828477_3; + +--echo # +--echo # Clean-up. +drop database mysqltest; + + --echo # --echo # End of 5.5 tests --echo # + +# Wait till all disconnects are completed +--source include/wait_until_count_sessions.inc diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fb5ed62ecdf..887115b38ad 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3157,6 +3157,10 @@ end: */ thd->temporary_tables= NULL; close_thread_tables(thd); + /* + Release metadata lock we might have acquired. + See comment in fill_schema_table_from_frm() for details. + */ thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp); thd->lex= old_lex; @@ -3339,6 +3343,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table, @param[in] db_name database name @param[in] table_name table name @param[in] schema_table_idx I_S table index + @param[in] open_tables_state_backup Open_tables_state object which is used + to save/restore original state of metadata + locks. @param[in] can_deadlock Indicates that deadlocks are possible due to metadata locks, so to avoid them we should not wait in case if @@ -3356,6 +3363,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables, LEX_STRING *db_name, LEX_STRING *table_name, enum enum_schema_tables schema_table_idx, + Open_tables_backup *open_tables_state_backup, bool can_deadlock) { TABLE *table= tables->table; @@ -3501,13 +3509,27 @@ end_share: end_unlock: mysql_mutex_unlock(&LOCK_open); - /* - Don't release the MDL lock, it can be part of a transaction. - If it is not, it will be released by the call to - MDL_context::rollback_to_savepoint() in the caller. - */ end: + /* + Release metadata lock we might have acquired. + + Without this step metadata locks acquired for each table processed + will be accumulated. In situation when a lot of tables are processed + by I_S query this will result in transaction with too many metadata + locks. As result performance of acquisition of new lock will suffer. + + Of course, the fact that we don't hold metadata lock on tables which + were processed till the end of I_S query makes execution less isolated + from concurrent DDL. Consequently one might get 'dirty' results from + such a query. But we have never promised serializability of I_S queries + anyway. + + We don't have any tables open since we took backup, so rolling back to + savepoint is safe. + */ + DBUG_ASSERT(thd->open_tables == NULL); + thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp); thd->clear_error(); return res; } @@ -3758,6 +3780,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) int res= fill_schema_table_from_frm(thd, tables, schema_table, db_name, table_name, schema_table_idx, + &open_tables_state_backup, can_deadlock); thd->pop_internal_handler(); From 4a6602223c79e25c7e07f70301de4f1b7975ec82 Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 15 Aug 2011 18:33:03 +0400 Subject: [PATCH 030/143] Cherry-picking follow-up patch for WL 5710 from mysql-5.5 to mysql-5.5.16-release. Original revision: # revision-id: bjorn.munch@oracle.com-20110812104938-peswzao46f4lvm9p # parent: dmitry.lenev@oracle.com-20110811155849-feyt3h7tj48padiu # committer: Bjorn Munch # branch nick: main-55 # timestamp: Fri 2011-08-12 12:49:38 +0200 # message: # Small followup fix to WL 5710: # Test mysql_plugin failed if version string ended in -mN --- mysql-test/t/mysql_plugin.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index 9e71db1a451..b07ce40e43a 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -288,11 +288,11 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQL_DATADIR --basedir=$MYSQ --echo # Show the help. --echo # replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ --exec $MYSQL_PLUGIN --help replace_result $MYSQL_PLUGIN mysql_plugin; ---replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ +--replace_regex /Ver [0-9.]+ Distrib [0-9.]+/Ver V.V.VV Distrib XX.XX.XX/ /XX-m[0-9]+/XX/ --exec $MYSQL_PLUGIN --version # From cfb4a7c2ff93a3a653f84d85e5f4b3df16e4f09a Mon Sep 17 00:00:00 2001 From: Alexander Nozdrin Date: Mon, 15 Aug 2011 18:34:42 +0400 Subject: [PATCH 031/143] Cherry-picking patch for 12777649 from mysql-5.5 to mysql-5.5.16-release. Original revision: # revision-id: georgi.kodinov@oracle.com-20110812135004-3z3yjy7krf374clu # parent: georgi.kodinov@oracle.com-20110812112536-dmh9i67tm8pqvz1a # committer: Georgi Kodinov # branch nick: B12777649-5.5 # timestamp: Fri 2011-08-12 16:50:04 +0300 # message: # Bug #12777649: "OS THREAD ID" REMOVED # # Pushed Calvin's patch. --- sql/sql_class.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 97a227c8bb5..0b1de2c47fa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -655,8 +655,8 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, const char *proc_info= thd->proc_info; len= my_snprintf(header, sizeof(header), - "MySQL thread id %lu, query id %lu", - thd->thread_id, (ulong) thd->query_id); + "MySQL thread id %lu, OS thread handle 0x%lx, query id %lu", + thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id); str.length(0); str.append(header, len); From cf5e5f837a06d29e6806eea3c47192dc6dd483da Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Mon, 15 Aug 2011 20:12:11 +0200 Subject: [PATCH 032/143] Merging into mysql-5.5.16-release. --- include/mysql/plugin.h | 13 +++++-- include/mysql/plugin_audit.h.pp | 1 + include/mysql/plugin_auth.h.pp | 1 + include/mysql/plugin_ftparser.h.pp | 3 +- plugin/audit_null/audit_null.c | 3 +- plugin/auth/auth_socket.c | 3 +- plugin/auth/dialog.c | 6 ++-- plugin/auth/qa_auth_interface.c | 3 +- plugin/auth/qa_auth_server.c | 3 +- plugin/auth/test_plugin.c | 6 ++-- plugin/daemon_example/daemon_example.cc | 3 +- plugin/fulltext/plugin_example.c | 3 +- plugin/semisync/semisync_master_plugin.cc | 3 +- plugin/semisync/semisync_slave_plugin.cc | 3 +- sql/ha_ndbcluster.cc | 3 +- sql/ha_partition.cc | 3 +- sql/log.cc | 3 +- sql/share/errmsg-utf8.txt | 5 +++ sql/sql_acl.cc | 6 ++-- sql/sql_plugin.cc | 32 +++++++++++++++++ storage/archive/ha_archive.cc | 3 +- storage/blackhole/ha_blackhole.cc | 3 +- storage/csv/ha_tina.cc | 3 +- storage/example/ha_example.cc | 3 +- storage/federated/ha_federated.cc | 3 +- storage/heap/ha_heap.cc | 3 +- storage/innobase/handler/ha_innodb.cc | 3 +- storage/innobase/handler/i_s.cc | 42 +++++++++++++++++++---- storage/myisam/ha_myisam.cc | 3 +- storage/myisammrg/ha_myisammrg.cc | 3 +- storage/perfschema/ha_perfschema.cc | 3 +- 31 files changed, 141 insertions(+), 37 deletions(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 1254a4530f5..3e6ab2410a5 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -71,7 +71,7 @@ typedef struct st_mysql_xid MYSQL_XID; Plugin API. Common for all plugin types. */ -#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102 +#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0103 /* The allowable types of plugins @@ -120,7 +120,7 @@ __MYSQL_DECLARE_PLUGIN(NAME, \ builtin_ ## NAME ## _sizeof_struct_st_plugin, \ builtin_ ## NAME ## _plugin) -#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}} +#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0,0}} /* declarations for SHOW STATUS support in plugins @@ -143,6 +143,14 @@ struct st_mysql_show_var { typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, char *); +/* + Constants for plugin flags. + */ + +#define PLUGIN_OPT_NO_INSTALL 1UL /* Not dynamically loadable */ +#define PLUGIN_OPT_NO_UNINSTALL 2UL /* Not dynamically unloadable */ + + /* declarations for server variables and command line options */ @@ -415,6 +423,7 @@ struct st_mysql_plugin struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; /* reserved for dependency checking */ + unsigned long flags; /* flags for plugin */ }; /************************************************************************* diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 16aaeab21c3..5d90b3efc37 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -101,6 +101,7 @@ struct st_mysql_plugin struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; + unsigned long flags; }; #include "plugin_ftparser.h" #include "plugin.h" diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index e65278c518e..3807556fd1b 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -101,6 +101,7 @@ struct st_mysql_plugin struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; + unsigned long flags; }; #include "plugin_ftparser.h" #include "plugin.h" diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index c29eac45b19..1a9fa0c759c 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -43,7 +43,7 @@ typedef enum _thd_wait_type_e { THD_WAIT_BINLOG= 8, THD_WAIT_GROUP_COMMIT= 9, THD_WAIT_SYNC= 10, - THD_WAIT_LAST= 11 + THD_WAIT_LAST= 11 } thd_wait_type; extern struct thd_wait_service_st { void (*thd_wait_begin_func)(void*, int); @@ -101,6 +101,7 @@ struct st_mysql_plugin struct st_mysql_show_var *status_vars; struct st_mysql_sys_var **system_vars; void * __reserved1; + unsigned long flags; }; #include "plugin_ftparser.h" struct st_mysql_daemon diff --git a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c index 3fe5fa993f0..469e5ae494c 100644 --- a/plugin/audit_null/audit_null.c +++ b/plugin/audit_null/audit_null.c @@ -154,7 +154,8 @@ mysql_declare_plugin(audit_null) 0x0002, /* version */ simple_status, /* status variables */ NULL, /* system variables */ - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/auth/auth_socket.c b/plugin/auth/auth_socket.c index 9d26a791b06..7990552ce8f 100644 --- a/plugin/auth/auth_socket.c +++ b/plugin/auth/auth_socket.c @@ -88,7 +88,8 @@ mysql_declare_plugin(socket_auth) 0x0100, NULL, NULL, - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/auth/dialog.c b/plugin/auth/dialog.c index 41312f95674..490de346a1e 100644 --- a/plugin/auth/dialog.c +++ b/plugin/auth/dialog.c @@ -153,7 +153,8 @@ mysql_declare_plugin(dialog) 0x0100, NULL, NULL, - NULL + NULL, + 0, }, { MYSQL_AUTHENTICATION_PLUGIN, @@ -167,7 +168,8 @@ mysql_declare_plugin(dialog) 0x0100, NULL, NULL, - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/auth/qa_auth_interface.c b/plugin/auth/qa_auth_interface.c index 0aa6c9ce20c..61e29fe9619 100644 --- a/plugin/auth/qa_auth_interface.c +++ b/plugin/auth/qa_auth_interface.c @@ -162,7 +162,8 @@ mysql_declare_plugin(test_plugin) 0x0100, NULL, NULL, - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/auth/qa_auth_server.c b/plugin/auth/qa_auth_server.c index 17171610200..4f1294e159f 100644 --- a/plugin/auth/qa_auth_server.c +++ b/plugin/auth/qa_auth_server.c @@ -82,6 +82,7 @@ mysql_declare_plugin(test_plugin) 0x0100, NULL, NULL, - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/auth/test_plugin.c b/plugin/auth/test_plugin.c index 912b6320579..efb32e8537d 100644 --- a/plugin/auth/test_plugin.c +++ b/plugin/auth/test_plugin.c @@ -125,7 +125,8 @@ mysql_declare_plugin(test_plugin) 0x0100, NULL, NULL, - NULL + NULL, + 0, }, { MYSQL_AUTHENTICATION_PLUGIN, @@ -139,7 +140,8 @@ mysql_declare_plugin(test_plugin) 0x0100, NULL, NULL, - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc index b53772648b4..fbfc0fb5f97 100644 --- a/plugin/daemon_example/daemon_example.cc +++ b/plugin/daemon_example/daemon_example.cc @@ -201,6 +201,7 @@ mysql_declare_plugin(daemon_example) 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c index a15c8e21b32..d5f6d869ea1 100644 --- a/plugin/fulltext/plugin_example.c +++ b/plugin/fulltext/plugin_example.c @@ -267,7 +267,8 @@ mysql_declare_plugin(ftexample) 0x0001, /* version */ simple_status, /* status variables */ simple_system_variables, /* system variables */ - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index ea87adf98c4..9a325018242 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -429,6 +429,7 @@ mysql_declare_plugin(semi_sync_master) 0x0100 /* 1.0 */, semi_sync_master_status_vars, /* status variables */ semi_sync_master_system_vars, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc index cfb04bdd276..d5472b9cc83 100644 --- a/plugin/semisync/semisync_slave_plugin.cc +++ b/plugin/semisync/semisync_slave_plugin.cc @@ -225,6 +225,7 @@ mysql_declare_plugin(semi_sync_slave) 0x0100 /* 1.0 */, semi_sync_slave_status_vars, /* status variables */ semi_sync_slave_system_vars, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index ac47c8dbc0e..610425ab735 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -11023,7 +11023,8 @@ mysql_declare_plugin(ndbcluster) 0x0100 /* 1.0 */, ndb_status_variables_export,/* status variables */ system_variables, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 9e22553ef0e..82bd39220a9 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -7183,7 +7183,8 @@ mysql_declare_plugin(partition) 0x0100, /* 1.0 */ NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/sql/log.cc b/sql/log.cc index 9080dcd7fa2..c6b41447d6a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -6604,6 +6604,7 @@ mysql_declare_plugin(binlog) 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b8f46f090ab..6f4edac285d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6415,3 +6415,8 @@ ER_ERROR_IN_TRIGGER_BODY ER_ERROR_IN_UNKNOWN_TRIGGER_BODY eng "Unknown trigger has an error in its body: '%-.256s'" +ER_PLUGIN_NO_UNINSTALL + eng "Plugin '%s' is marked as not dynamically uninstallable. You have to stop the server to uninstall it." + +ER_PLUGIN_NO_INSTALL + eng "Plugin '%s' is marked as not dynamically installable. You have to stop the server to install it." diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 06a67edda36..87beb71cca5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9651,7 +9651,8 @@ mysql_declare_plugin(mysql_password) 0x0100, /* Version (1.0) */ NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ }, { MYSQL_AUTHENTICATION_PLUGIN, /* type constant */ @@ -9665,7 +9666,8 @@ mysql_declare_plugin(mysql_password) 0x0100, /* Version (1.0) */ NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 015cbe31a15..5f5e73091ff 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -539,6 +539,11 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) #endif } + /* + What's the purpose of this loop? If the goal is to catch a + missing 0 record at the end of a list, it will fail miserably + since the compiler is likely to optimize this away. /Matz + */ for (i= 0; ((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info; i++) @@ -567,6 +572,23 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) } plugin_dl.plugins= (struct st_mysql_plugin *)sym; + /* + If report is REPORT_TO_USER, we were called from + mysql_install_plugin. Otherwise, we are called directly or + indirectly from plugin_init. + */ + if (report == REPORT_TO_USER) + { + st_mysql_plugin *plugin= plugin_dl.plugins; + for ( ; plugin->info ; ++plugin) + if (plugin->flags & PLUGIN_OPT_NO_INSTALL) + { + report_error(report, ER_PLUGIN_NO_INSTALL, plugin->name); + free_plugin_mem(&plugin_dl); + DBUG_RETURN(0); + } + } + /* Duplicate and convert dll name */ plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1; if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0)))) @@ -1884,6 +1906,16 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); goto err; } + /* + Error message for ER_PLUGIN_IS_PERMANENT is not suitable for + plugins marked as not dynamically uninstallable, so we have a + separate one instead of changing the old one. + */ + if (plugin->plugin->flags & PLUGIN_OPT_NO_UNINSTALL) + { + my_error(ER_PLUGIN_NO_UNINSTALL, MYF(0), plugin->plugin->name); + goto err; + } plugin->state= PLUGIN_IS_DELETED; if (plugin->ref_count) diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index aec13a5fe6c..345c1b6835f 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1766,7 +1766,8 @@ mysql_declare_plugin(archive) 0x0300 /* 3.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index 3905f4f18c3..c01bd7d27f5 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -448,6 +448,7 @@ mysql_declare_plugin(blackhole) 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 1cca9c4e686..ba468c53716 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -1766,7 +1766,8 @@ mysql_declare_plugin(csv) 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index f7c9187aad0..44165ee6190 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -1008,6 +1008,7 @@ mysql_declare_plugin(example) 0x0001 /* 0.1 */, func_status, /* status variables */ example_system_variables, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 858895b1add..06bf180283d 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -3481,6 +3481,7 @@ mysql_declare_plugin(federated) 0x0100 /* 1.0 */, NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 218aa35700f..a53b588ab69 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -825,6 +825,7 @@ mysql_declare_plugin(heap) 0x0100, /* 1.0 */ NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 24407c7b053..4648b4300b8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11402,7 +11402,8 @@ mysql_declare_plugin(innobase) INNODB_VERSION_SHORT, innodb_status_variables_export,/* status variables */ innobase_system_variables, /* system variables */ - NULL /* reserved */ + NULL, /* reserved */ + 0, /* flags */ }, i_s_innodb_trx, i_s_innodb_locks, diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index de5cc682078..e9905930699 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -638,7 +638,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_trx = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_locks */ @@ -904,7 +908,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_locks = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_lock_waits */ @@ -1087,7 +1095,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_lock_waits = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /*******************************************************************//** @@ -1420,7 +1432,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmp = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmp_reset = @@ -1470,7 +1486,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmp_reset = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /* Fields of the dynamic table information_schema.innodb_cmpmem. */ @@ -1711,7 +1731,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmpmem = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmpmem_reset = @@ -1761,7 +1785,11 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_cmpmem_reset = /* reserved for dependency checking */ /* void* */ - STRUCT_FLD(__reserved1, NULL) + STRUCT_FLD(__reserved1, NULL), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, 0UL), }; /*******************************************************************//** diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 8f7400308ba..b2b64054cf9 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -2086,7 +2086,8 @@ mysql_declare_plugin(myisam) 0x0100, /* 1.0 */ NULL, /* status variables */ myisam_sysvars, /* system variables */ - NULL + NULL, + 0, } mysql_declare_plugin_end; diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index c76e9ee0bfe..b7e043c99f1 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1687,6 +1687,7 @@ mysql_declare_plugin(myisammrg) 0x0100, /* 1.0 */ NULL, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc index 8e3486a4fa3..5cc10b0f35a 100644 --- a/storage/perfschema/ha_perfschema.cc +++ b/storage/perfschema/ha_perfschema.cc @@ -166,7 +166,8 @@ mysql_declare_plugin(perfschema) 0x0001 /* 0.1 */, pfs_status_vars, /* status variables */ NULL, /* system variables */ - NULL /* config options */ + NULL, /* config options */ + 0, /* flags */ } mysql_declare_plugin_end; From e4bda8b6b5c1a9b80051704614a37bfe26dc628a Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 16 Aug 2011 11:08:10 +0200 Subject: [PATCH 033/143] Bug #11759877 52223: TEST "PLUGIN_DIR_BASIC" DOES NOT SUPPORT RPM BUILD (TEST) DIRECTORY STRUC Undo previous fix, it is not reliable Drop setting $MYSQL_LIBDIR, mtr can't be sure anyway Test is set to override plugin-dir to some known existing dir --- mysql-test/include/mysqld--help.inc | 2 +- mysql-test/mysql-test-run.pl | 6 ------ .../suite/sys_vars/r/plugin_dir_basic.result | 10 +++++----- .../suite/sys_vars/t/plugin_dir_basic-master.opt | 1 + mysql-test/suite/sys_vars/t/plugin_dir_basic.test | 14 +++++++------- 5 files changed, 14 insertions(+), 19 deletions(-) create mode 100644 mysql-test/suite/sys_vars/t/plugin_dir_basic-master.opt diff --git a/mysql-test/include/mysqld--help.inc b/mysql-test/include/mysqld--help.inc index 5d20cff2c13..380a7f6c8cf 100644 --- a/mysql-test/include/mysqld--help.inc +++ b/mysql-test/include/mysqld--help.inc @@ -26,7 +26,7 @@ perl; # And substitute the content some environment variables with their # names: - @env=qw/MYSQLTEST_VARDIR MYSQL_TEST_DIR MYSQL_LIBDIR MYSQL_CHARSETSDIR MYSQL_SHAREDIR/; + @env=qw/MYSQLTEST_VARDIR MYSQL_TEST_DIR MYSQL_CHARSETSDIR MYSQL_SHAREDIR/; $re1=join('|', @skipvars, @plugins); $re2=join('|', @plugins); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ec0ca74b1d1..168115cbc6b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2295,12 +2295,6 @@ sub environment_setup { $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'port'}; $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir; $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; - # Used for guessing default plugin dir, we can't really know for sure - $ENV{'MYSQL_LIBDIR'}= "$basedir/lib"; - # Override if this does not exist, but lib64 does (best effort) - if (! -d "$basedir/lib" && -d "$basedir/lib64") { - $ENV{'MYSQL_LIBDIR'}= "$basedir/lib64"; - } $ENV{'MYSQL_BINDIR'}= "$bindir"; $ENV{'MYSQL_SHAREDIR'}= $path_language; $ENV{'MYSQL_CHARSETSDIR'}= $path_charsetsdir; diff --git a/mysql-test/suite/sys_vars/r/plugin_dir_basic.result b/mysql-test/suite/sys_vars/r/plugin_dir_basic.result index f81cae24dda..a5f36de73fa 100644 --- a/mysql-test/suite/sys_vars/r/plugin_dir_basic.result +++ b/mysql-test/suite/sys_vars/r/plugin_dir_basic.result @@ -1,20 +1,20 @@ select @@global.plugin_dir; @@global.plugin_dir -MYSQL_LIBDIR/plugin +MYSQL_TMP_DIR select @@session.plugin_dir; ERROR HY000: Variable 'plugin_dir' is a GLOBAL variable show global variables like 'plugin_dir'; Variable_name Value -plugin_dir MYSQL_LIBDIR/plugin +plugin_dir MYSQL_TMP_DIR show session variables like 'plugin_dir'; Variable_name Value -plugin_dir MYSQL_LIBDIR/plugin +plugin_dir MYSQL_TMP_DIR select * from information_schema.global_variables where variable_name='plugin_dir'; VARIABLE_NAME VARIABLE_VALUE -PLUGIN_DIR MYSQL_LIBDIR/plugin +PLUGIN_DIR MYSQL_TMP_DIR select * from information_schema.session_variables where variable_name='plugin_dir'; VARIABLE_NAME VARIABLE_VALUE -PLUGIN_DIR MYSQL_LIBDIR/plugin +PLUGIN_DIR MYSQL_TMP_DIR set global plugin_dir=1; ERROR HY000: Variable 'plugin_dir' is a read only variable set session plugin_dir=1; diff --git a/mysql-test/suite/sys_vars/t/plugin_dir_basic-master.opt b/mysql-test/suite/sys_vars/t/plugin_dir_basic-master.opt new file mode 100644 index 00000000000..69a9f0def2a --- /dev/null +++ b/mysql-test/suite/sys_vars/t/plugin_dir_basic-master.opt @@ -0,0 +1 @@ +--plugin-dir=$MYSQL_TMP_DIR diff --git a/mysql-test/suite/sys_vars/t/plugin_dir_basic.test b/mysql-test/suite/sys_vars/t/plugin_dir_basic.test index d714950c807..59889f7ecb2 100644 --- a/mysql-test/suite/sys_vars/t/plugin_dir_basic.test +++ b/mysql-test/suite/sys_vars/t/plugin_dir_basic.test @@ -3,20 +3,20 @@ # # -# on windows it's /lib/plugin -# on unix it's /lib/mysql/plugin +# Don't rely on being able to guess the correct default. +# -master.opt file for this test sets plugin_dir to a known directory # ---replace_result $MYSQL_LIBDIR MYSQL_LIBDIR /mysql/ / +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR /mysql/ / select @@global.plugin_dir; --error ER_INCORRECT_GLOBAL_LOCAL_VAR select @@session.plugin_dir; ---replace_result $MYSQL_LIBDIR MYSQL_LIBDIR /mysql/ / +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR /mysql/ / show global variables like 'plugin_dir'; ---replace_result $MYSQL_LIBDIR MYSQL_LIBDIR /mysql/ / +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR /mysql/ / show session variables like 'plugin_dir'; ---replace_result $MYSQL_LIBDIR MYSQL_LIBDIR /mysql/ / +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR /mysql/ / select * from information_schema.global_variables where variable_name='plugin_dir'; ---replace_result $MYSQL_LIBDIR MYSQL_LIBDIR /mysql/ / +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR /mysql/ / select * from information_schema.session_variables where variable_name='plugin_dir'; # From 887ac6774f9d33b64d7c316e9310038592ec6a83 Mon Sep 17 00:00:00 2001 From: Sneha Modi Date: Tue, 16 Aug 2011 16:06:34 +0530 Subject: [PATCH 034/143] Fixing a few broken tests. --- .../r/innodb_file_per_table_basic.result | 27 ++++++++++++++++--- .../r/innodb_lock_wait_timeout_basic.result | 21 +++++++++++---- .../t/innodb_autoinc_lock_mode_basic.test | 3 +-- .../t/innodb_fast_shutdown_basic.test | 4 +-- .../t/innodb_file_per_table_basic.test | 22 ++++++++++++--- .../sys_vars/t/innodb_io_capacity_basic.test | 4 +++ .../t/innodb_lock_wait_timeout_basic.test | 24 ++++++++++------- .../t/innodb_max_dirty_pages_pct_basic.test | 4 +-- 8 files changed, 81 insertions(+), 28 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result index 163eb31f686..ecf11351cd9 100644 --- a/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result @@ -1,13 +1,29 @@ +SET @start_global_value = @@global.innodb_file_per_table; +SELECT @start_global_value; +@start_global_value +0 '#---------------------BS_STVARS_028_01----------------------#' SELECT COUNT(@@GLOBAL.innodb_file_per_table); COUNT(@@GLOBAL.innodb_file_per_table) 1 1 Expected '#---------------------BS_STVARS_028_02----------------------#' -SELECT COUNT(@@GLOBAL.innodb_file_per_table); -COUNT(@@GLOBAL.innodb_file_per_table) +SET @@global.innodb_file_per_table = 0; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 +SET @@global.innodb_file_per_table ='On' ; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +1 +SET @@global.innodb_file_per_table ='Off' ; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 +SET @@global.innodb_file_per_table = 1; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table 1 -1 Expected '#---------------------BS_STVARS_028_03----------------------#' SELECT IF(@@GLOBAL.innodb_file_per_table,'ON','OFF') = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -47,4 +63,7 @@ COUNT(@@GLOBAL.innodb_file_per_table) 1 Expected SELECT innodb_file_per_table = @@SESSION.innodb_file_per_table; ERROR 42S22: Unknown column 'innodb_file_per_table' in 'field list' -Expected error 'Readonly variable' +SET @@global.innodb_file_per_table = @start_global_value; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 diff --git a/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result b/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result index 89960e5860f..1dcc2d554ce 100644 --- a/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result @@ -1,13 +1,21 @@ +SET @start_global_value=@@global.innodb_lock_wait_timeout; +SELECT @start_global_value; +@start_global_value +50 '#---------------------BS_STVARS_032_01----------------------#' SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); COUNT(@@GLOBAL.innodb_lock_wait_timeout) 1 1 Expected '#---------------------BS_STVARS_032_02----------------------#' -SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); -COUNT(@@GLOBAL.innodb_lock_wait_timeout) -1 -1 Expected +SET global innodb_lock_wait_timeout=60; +SELECT @@global.innodb_lock_wait_timeout; +@@global.innodb_lock_wait_timeout +60 +SET session innodb_lock_wait_timeout=60; +SELECT @@session.innodb_lock_wait_timeout; +@@session.innodb_lock_wait_timeout +60 '#---------------------BS_STVARS_032_03----------------------#' SELECT @@GLOBAL.innodb_lock_wait_timeout = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -47,4 +55,7 @@ COUNT(@@GLOBAL.innodb_lock_wait_timeout) 1 Expected SELECT innodb_lock_wait_timeout = @@SESSION.innodb_lock_wait_timeout; ERROR 42S22: Unknown column 'innodb_lock_wait_timeout' in 'field list' -Expected error 'Readonly variable' +SET @@global.innodb_lock_wait_timeout = @start_global_value; +SELECT @@global.innodb_lock_wait_timeout; +@@global.innodb_lock_wait_timeout +50 diff --git a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test index 5b6fa943bbe..e07234a9152 100644 --- a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test @@ -1,8 +1,7 @@ ################# mysql-test\t\innodb_autoinc_lock_mode_basic.test ############ # # # Variable Name: innodb_autoinc_lock_mode # -# Scope: GLOBAL # -# Access Type: Dynamic # +# Access Type: Static # # Data Type: Numeric # # Default Value: 1 # # Range: 0,1,2 # diff --git a/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test b/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test index 636309a3088..e1b62046313 100644 --- a/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test @@ -3,9 +3,9 @@ # Variable Name: innodb_fast_shutdown # # Scope: GLOBAL # # Access Type: Dynamic # -# Data Type: boolean # +# Data Type: numeric # # Default Value: 1 # -# Valid Values: 0,1 # +# Valid Values: 0,1,2 # # # # # # Creation Date: 2008-02-20 # diff --git a/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test index 76a50df8879..1478d6df2e9 100644 --- a/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test @@ -4,7 +4,7 @@ # # # Variable Name: innodb_file_per_table # # Scope: Global # -# Access Type: Static # +# Access Type: Dynamic # # Data Type: boolean # # # # # @@ -24,6 +24,10 @@ --source include/have_innodb.inc +SET @start_global_value = @@global.innodb_file_per_table; +SELECT @start_global_value; + + --echo '#---------------------BS_STVARS_028_01----------------------#' #################################################################### # Displaying default value # @@ -37,11 +41,17 @@ SELECT COUNT(@@GLOBAL.innodb_file_per_table); # Check if Value can set # #################################################################### -SELECT COUNT(@@GLOBAL.innodb_file_per_table); ---echo 1 Expected +SET @@global.innodb_file_per_table = 0; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table ='On' ; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table ='Off' ; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table = 1; +SELECT @@global.innodb_file_per_table; --echo '#---------------------BS_STVARS_028_03----------------------#' ################################################################# @@ -93,6 +103,10 @@ SELECT COUNT(@@GLOBAL.innodb_file_per_table); --Error ER_BAD_FIELD_ERROR SELECT innodb_file_per_table = @@SESSION.innodb_file_per_table; ---echo Expected error 'Readonly variable' +# +# Cleanup +# +SET @@global.innodb_file_per_table = @start_global_value; +SELECT @@global.innodb_file_per_table; diff --git a/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test b/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test index 3f00b50cf08..0ced5800d4b 100644 --- a/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test @@ -54,5 +54,9 @@ select * from information_schema.global_variables where variable_name='innodb_io set global innodb_io_capacity=100; select @@global.innodb_io_capacity; +# +# cleanup +# + SET @@global.innodb_io_capacity = @start_global_value; SELECT @@global.innodb_io_capacity; diff --git a/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test b/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test index 8cfd23fd6e7..f80b8e48736 100644 --- a/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test @@ -3,13 +3,13 @@ ################## mysql-test\t\innodb_lock_wait_timeout_basic.test ########### # # # Variable Name: innodb_lock_wait_timeout # -# Scope: Global # -# Access Type: Static # +# Scope: Global , Session # +# Access Type: Dynamic # # Data Type: numeric # # # # # # Creation Date: 2008-02-07 # -# Author : Sharique Abdullah # +# Author : Sharique Abdullah # # # # # # Description:Test Cases of Dynamic System Variable innodb_lock_wait_timeout # @@ -24,6 +24,9 @@ --source include/have_innodb.inc +SET @start_global_value=@@global.innodb_lock_wait_timeout; +SELECT @start_global_value; + --echo '#---------------------BS_STVARS_032_01----------------------#' #################################################################### # Displaying default value # @@ -37,11 +40,10 @@ SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); # Check if Value can set # #################################################################### -SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); ---echo 1 Expected - - - +SET global innodb_lock_wait_timeout=60; +SELECT @@global.innodb_lock_wait_timeout; +SET session innodb_lock_wait_timeout=60; +SELECT @@session.innodb_lock_wait_timeout; --echo '#---------------------BS_STVARS_032_03----------------------#' ################################################################# @@ -89,6 +91,10 @@ SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); --Error ER_BAD_FIELD_ERROR SELECT innodb_lock_wait_timeout = @@SESSION.innodb_lock_wait_timeout; ---echo Expected error 'Readonly variable' +# +# Cleanup +# +SET @@global.innodb_lock_wait_timeout = @start_global_value; +SELECT @@global.innodb_lock_wait_timeout; diff --git a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test index 38c3acd92a2..7e70ed11351 100644 --- a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test @@ -4,8 +4,8 @@ # Scope: GLOBAL # # Access Type: Dynamic # # Data Type: Numeric # -# Default Value: 90 # -# Range: 0-1000 # +# Default Value: 75 # +# Range: 0-99 # # # # # # Creation Date: 2008-02-07 # From c79b036ed1804bb06073965badf2b2fa18b597c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Aug 2011 19:29:06 +0200 Subject: [PATCH 035/143] fix for bug 55713 innochecksum is NOT built with large file support enabled --- extra/innochecksum.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extra/innochecksum.c b/extra/innochecksum.c index 7ad900d16d3..f066cab2b3a 100644 --- a/extra/innochecksum.c +++ b/extra/innochecksum.c @@ -25,12 +25,7 @@ Published with a permission. */ -/* needed to have access to 64 bit file functions */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE - -#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */ - +#include #include #include #include From b213e7f814c7145a98b689710f14a479cf700912 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Aug 2011 00:34:11 +0200 Subject: [PATCH 036/143] 2nd fix for Bug #55713 innochecksum is NOT built with large file support enabled --- extra/innochecksum.c | 1 - 1 file changed, 1 deletion(-) diff --git a/extra/innochecksum.c b/extra/innochecksum.c index f066cab2b3a..b55b510b888 100644 --- a/extra/innochecksum.c +++ b/extra/innochecksum.c @@ -48,7 +48,6 @@ /* another argument to specify page ranges... seek to right spot and go from there */ typedef unsigned long int ulint; -typedef unsigned char uchar; /* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */ ulint mach_read_from_4(uchar *b) From 95fa7fab3b70e5117d757d9df42ac9d7040fea03 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Tue, 16 Aug 2011 18:07:59 -0700 Subject: [PATCH 037/143] Fix bug #11830883, SUPPORT "CORRUPTED" BIT FOR INNODB TABLES AND INDEXES. Also addressed issues in bug #11745133, where we could mark a table corrupted instead of crashing the server when found a corrupted buffer/page if the table created with innodb_file_per_table on. --- include/my_base.h | 5 +- .../suite/innodb/r/innodb_corrupt_bit.result | 81 ++++++++ .../suite/innodb/t/innodb_corrupt_bit.test | 135 +++++++++++++ mysql-test/suite/sys_vars/r/all_vars.result | 2 + mysys/my_handler_errors.h | 3 +- sql/handler.cc | 4 + sql/share/errmsg-utf8.txt | 2 + storage/innobase/buf/buf0buf.c | 66 ++++++- storage/innobase/buf/buf0lru.c | 16 ++ storage/innobase/dict/dict0dict.c | 179 +++++++++++++++++- storage/innobase/dict/dict0load.c | 93 ++++++++- storage/innobase/handler/ha_innodb.cc | 139 ++++++++++++-- storage/innobase/include/buf0lru.h | 11 ++ storage/innobase/include/db0err.h | 1 + storage/innobase/include/dict0boot.h | 6 +- storage/innobase/include/dict0dict.h | 81 +++++++- storage/innobase/include/dict0dict.ic | 46 ++++- storage/innobase/include/dict0mem.h | 14 +- storage/innobase/include/dict0types.h | 3 +- storage/innobase/include/srv0srv.h | 4 + storage/innobase/pars/pars0opt.c | 2 +- storage/innobase/row/row0ins.c | 11 +- storage/innobase/row/row0merge.c | 5 +- storage/innobase/row/row0mysql.c | 3 +- storage/innobase/row/row0purge.c | 13 ++ storage/innobase/row/row0sel.c | 7 + storage/innobase/row/row0uins.c | 4 +- storage/innobase/row/row0umod.c | 25 +++ storage/innobase/row/row0upd.c | 7 + storage/innobase/ut/ut0ut.c | 2 + 30 files changed, 915 insertions(+), 55 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb_corrupt_bit.result create mode 100644 mysql-test/suite/innodb/t/innodb_corrupt_bit.test diff --git a/include/my_base.h b/include/my_base.h index f6afc891281..cc02b0080d9 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -446,8 +446,9 @@ enum ha_base_keytype { #define HA_ERR_FILE_TOO_SHORT 175 /* File too short */ #define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */ #define HA_ERR_TOO_MANY_CONCURRENT_TRXS 177 /*Too many active concurrent transactions */ -#define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */ -#define HA_ERR_LAST 178 /* Copy of last error nr */ +#define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */ +#define HA_ERR_INDEX_CORRUPT 179 /* Index corrupted */ +#define HA_ERR_LAST 179 /* Copy of last error nr */ /* Number of different errors */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result new file mode 100644 index 00000000000..4253adc93aa --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result @@ -0,0 +1,81 @@ +set names utf8; +CREATE TABLE corrupt_bit_test_ā( +a INT AUTO_INCREMENT PRIMARY KEY, +b CHAR(100), +c INT, +z INT, +INDEX(b)) +ENGINE=InnoDB; +INSERT INTO corrupt_bit_test_ā VALUES(0,'x',1, 1); +CREATE UNIQUE INDEX idxā ON corrupt_bit_test_ā(c, b); +CREATE UNIQUE INDEX idxē ON corrupt_bit_test_ā(z, b); +SELECT * FROM corrupt_bit_test_ā; +a b c z +1 x 1 1 +select @@unique_checks; +@@unique_checks +0 +select @@innodb_change_buffering_debug; +@@innodb_change_buffering_debug +1 +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1,z+1 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+10,z+10 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+20,z+20 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+50,z+50 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+100,z+100 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+200,z+200 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+400,z+400 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+800,z+800 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1600,z+1600 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+4000,z+4000 FROM corrupt_bit_test_ā; +select count(*) from corrupt_bit_test_ā; +count(*) +1024 +CREATE INDEX idx3 ON corrupt_bit_test_ā(b, c); +INSERT INTO corrupt_bit_test_ā VALUES(13000,'x',1,1); +CREATE INDEX idx4 ON corrupt_bit_test_ā(b, z); +check table corrupt_bit_test_ā; +Table Op Msg_type Msg_text +test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxā" is corrupted. +test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxē" is corrupted. +test.corrupt_bit_test_ā check error Corrupt +select c from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +select z from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +show warnings; +Level Code Message +Warning 179 InnoDB: Index "idxē" for table "test/corrupt_bit_test_@1s" is marked as corrupted +Error 1034 Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +select * from corrupt_bit_test_ā use index(primary) where a = 10001; +a b c z +10001 a 20001 20001 +begin; +insert into corrupt_bit_test_ā values (10002, "a", 20002, 20002); +delete from corrupt_bit_test_ā where a = 10001; +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +rollback; +drop index idxā on corrupt_bit_test_ā; +check table corrupt_bit_test_ā; +Table Op Msg_type Msg_text +test.corrupt_bit_test_ā check Warning InnoDB: Index "idxē" is marked as corrupted +test.corrupt_bit_test_ā check error Corrupt +set names utf8; +select z from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +drop index idxē on corrupt_bit_test_ā; +select z from corrupt_bit_test_ā limit 10; +z +20001 +1 +1 +2 +11 +12 +21 +22 +31 +32 +drop table corrupt_bit_test_ā; +SET GLOBAL innodb_change_buffering_debug = 0; diff --git a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test new file mode 100644 index 00000000000..7d98a8e4a03 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test @@ -0,0 +1,135 @@ +# +# Test for persistent corrupt bit for corrupted index and table +# +-- source include/have_innodb.inc + +# This test needs debug server +--source include/have_debug.inc + +-- disable_query_log +# This test setup is extracted from bug56680.test: +# The flag innodb_change_buffering_debug is only available in debug builds. +# It instructs InnoDB to try to evict pages from the buffer pool when +# change buffering is possible, so that the change buffer will be used +# whenever possible. +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET @innodb_change_buffering_debug_orig = @@innodb_change_buffering_debug; +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = 1; + +# Turn off Unique Check to create corrupted index with dup key +SET UNIQUE_CHECKS=0; + +-- enable_query_log + +set names utf8; + +CREATE TABLE corrupt_bit_test_ā( + a INT AUTO_INCREMENT PRIMARY KEY, + b CHAR(100), + c INT, + z INT, + INDEX(b)) +ENGINE=InnoDB; + +INSERT INTO corrupt_bit_test_ā VALUES(0,'x',1, 1); + +# This is the first unique index we intend to corrupt +CREATE UNIQUE INDEX idxā ON corrupt_bit_test_ā(c, b); + +# This is the second unique index we intend to corrupt +CREATE UNIQUE INDEX idxē ON corrupt_bit_test_ā(z, b); + +SELECT * FROM corrupt_bit_test_ā; + +select @@unique_checks; +select @@innodb_change_buffering_debug; + +# Create enough rows for the table, so that the insert buffer will be +# used for modifying the secondary index page. There must be multiple +# index pages, because changes to the root page are never buffered. + +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1,z+1 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+10,z+10 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+20,z+20 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+50,z+50 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+100,z+100 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+200,z+200 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+400,z+400 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+800,z+800 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1600,z+1600 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+4000,z+4000 FROM corrupt_bit_test_ā; + +select count(*) from corrupt_bit_test_ā; + +CREATE INDEX idx3 ON corrupt_bit_test_ā(b, c); + +# Create a dup key error on index "idxē" and "idxā" by inserting a dup value +INSERT INTO corrupt_bit_test_ā VALUES(13000,'x',1,1); + +# creating an index should succeed even if other secondary indexes are corrupted +CREATE INDEX idx4 ON corrupt_bit_test_ā(b, z); + +# Check table will find the unique indexes corrupted +# with dup key +check table corrupt_bit_test_ā; + +# This selection intend to use the corrupted index. Expect to fail +-- error ER_NOT_KEYFILE +select c from corrupt_bit_test_ā; + +-- error ER_NOT_KEYFILE +select z from corrupt_bit_test_ā; + +show warnings; + +# Since corrupted index is a secondary index, we only disable such +# index and allow other DML to proceed +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); + +# This does not use the corrupted index, expect to succeed +select * from corrupt_bit_test_ā use index(primary) where a = 10001; + +# Some more DMLs +begin; +insert into corrupt_bit_test_ā values (10002, "a", 20002, 20002); +delete from corrupt_bit_test_ā where a = 10001; +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +rollback; + +# Drop one corrupted index before reboot +drop index idxā on corrupt_bit_test_ā; + +check table corrupt_bit_test_ā; + +# Shut down the server +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +-- shutdown_server 20 +-- source include/wait_until_disconnected.inc + +# Restart the server +-- disable_query_log +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect +-- enable_query_log + +set names utf8; + +# The index is marked as suspect in Sys_indexes too, so after server +# reboot, the attempt to use the index will fail too. +-- error ER_NOT_KEYFILE +select z from corrupt_bit_test_ā; + +# Drop the corrupted index +drop index idxē on corrupt_bit_test_ā; + +# Now select back to normal +select z from corrupt_bit_test_ā limit 10; + +# Drop table +drop table corrupt_bit_test_ā; + +-- error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = 0; diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 715ad9e2c15..edd6f57e32d 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,7 +11,9 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: +INNODB_FORCE_LOAD_CORRUPTED INNODB_LARGE_PREFIX +INNODB_FORCE_LOAD_CORRUPTED INNODB_LARGE_PREFIX drop table t1; drop table t2; diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h index 3bd83398e81..428a58b0767 100644 --- a/mysys/my_handler_errors.h +++ b/mysys/my_handler_errors.h @@ -81,7 +81,8 @@ static const char *handler_error_messages[]= "File to short; Expected more data in file", "Read page with wrong checksum", "Too many active concurrent transactions", - "Index column length exceeds limit" + "Index column length exceeds limit", + "Index corrupted" }; extern void my_handler_error_register(void); diff --git a/sql/handler.cc b/sql/handler.cc index 580677242bd..db1eea6484b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -358,6 +358,7 @@ int ha_init_errors(void) SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE)); SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS)); SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG)); + SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT)); /* Register the error messages for use with my_error(). */ return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST); @@ -2865,6 +2866,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_INDEX_COL_TOO_LONG: textno= ER_INDEX_COLUMN_TOO_LONG; break; + case HA_ERR_INDEX_CORRUPT: + textno= ER_INDEX_CORRUPT; + break; default: { /* The error was "unknown" to this function. diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b8f46f090ab..519d693f96d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6415,3 +6415,5 @@ ER_ERROR_IN_TRIGGER_BODY ER_ERROR_IN_UNKNOWN_TRIGGER_BODY eng "Unknown trigger has an error in its body: '%-.256s'" +ER_INDEX_CORRUPT + eng "Index %s is corrupted" diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 648e53ac4a6..565fbe7bbf4 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3473,6 +3473,55 @@ buf_page_create( return(block); } +/********************************************************************//** +Mark a table with the specified space pointed by bpage->space corrupted. +Also remove the bpage from LRU list. +@return TRUE if successful */ +static +ibool +buf_mark_space_corrupt( +/*===================*/ + buf_page_t* bpage) /*!< in: pointer to the block in question */ +{ + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + const ibool uncompressed = (buf_page_get_state(bpage) + == BUF_BLOCK_FILE_PAGE); + ulint space = bpage->space; + ulint offset = bpage->offset; + ibool ret = TRUE; + + /* First unfix and release lock on the bpage */ + buf_pool_mutex_enter(buf_pool); + mutex_enter(buf_page_get_mutex(bpage)); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); + ut_ad(bpage->buf_fix_count == 0); + + /* Set BUF_IO_NONE before we remove the block from LRU list */ + buf_page_set_io_fix(bpage, BUF_IO_NONE); + + if (uncompressed) { + rw_lock_x_unlock_gen( + &((buf_block_t*) bpage)->lock, + BUF_IO_READ); + } + + /* Find the table with specified space id, and mark it corrupted */ + if (dict_set_corrupted_by_space(space)) { + ut_ad(bpage->space == space && bpage->offset == offset); + buf_LRU_free_one_page(bpage); + } else { + ret = FALSE; + } + + ut_ad(buf_pool->n_pend_reads > 0); + buf_pool->n_pend_reads--; + + mutex_exit(buf_page_get_mutex(bpage)); + buf_pool_mutex_exit(buf_pool); + + return(ret); +} + /********************************************************************//** Completes an asynchronous read or write request of a file page to or from the buffer pool. */ @@ -3598,10 +3647,19 @@ corrupt: "InnoDB: about forcing recovery.\n", stderr); if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { - fputs("InnoDB: Ending processing because of" - " a corrupt database page.\n", - stderr); - exit(1); + /* If page space id is larger than TRX_SYS_SPACE + (0), we will attempt to mark the corresponding + table as corrupted instead of crashing server */ + if (bpage->space > TRX_SYS_SPACE + && buf_mark_space_corrupt(bpage)) { + return; + } else { + fputs("InnoDB: Ending processing" + " because of" + " a corrupt database page.\n", + stderr); + ut_error; + } } } diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 93c98719e29..b5ca21e14a6 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -1885,6 +1885,22 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +/******************************************************************//** +Remove one page from LRU list and put it to free list */ +UNIV_INTERN +void +buf_LRU_free_one_page( +/*==================*/ + buf_page_t* bpage) /*!< in/out: block, must contain a file page and + be in a state where it can be freed; there + may or may not be a hash index to the page */ +{ + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) + != BUF_BLOCK_ZIP_FREE) { + buf_LRU_block_free_hashed_page((buf_block_t*) bpage); + } +} + /**********************************************************************//** Updates buf_pool->LRU_old_ratio for one buffer pool instance. @return updated old_pct */ diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index ead86e37380..dfb733cb36c 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -54,6 +54,7 @@ UNIV_INTERN dict_index_t* dict_ind_compact; #include "row0merge.h" #include "m_ctype.h" /* my_isspace() */ #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/ +#include "row0upd.h" #include @@ -611,8 +612,7 @@ dict_table_get_on_id( { dict_table_t* table; - if (table_id <= DICT_FIELDS_ID - || trx->dict_operation_lock_mode == RW_X_LATCH) { + if (trx->dict_operation_lock_mode == RW_X_LATCH) { /* Note: An X latch implies that the transaction already owns the dictionary mutex. */ @@ -5046,4 +5046,179 @@ dict_close(void) rw_lock_free(&dict_table_stats_latches[i]); } } + +/**********************************************************************//** +Find a table in dict_sys->table_LRU list with specified space id +@return table if found, NULL if not */ +static +dict_table_t* +dict_find_table_by_space( +/*=====================*/ + ulint space_id) /*!< in: space ID */ +{ + dict_table_t* table; + ulint num_item; + ulint count = 0; + + ut_ad(space_id > 0); + + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + num_item = UT_LIST_GET_LEN(dict_sys->table_LRU); + + /* This function intentionally does not acquire mutex as it is used + by error handling code in deep call stack as last means to avoid + killing the server, so it worth to risk some consequencies for + the action. */ + while (table && count < num_item) { + if (table->space == space_id) { + return(table); + } + + table = UT_LIST_GET_NEXT(table_LRU, table); + count++; + } + + return(NULL); +} + +/**********************************************************************//** +Flags a table with specified space_id corrupted in the data dictionary +cache +@return TRUE if successful */ +UNIV_INTERN +ibool +dict_set_corrupted_by_space( +/*========================*/ + ulint space_id) /*!< in: space ID */ +{ + dict_table_t* table; + + table = dict_find_table_by_space(space_id); + + if (!table) { + return(FALSE); + } + + /* mark the table->corrupted bit only, since the caller + could be too deep in the stack for SYS_INDEXES update */ + table->corrupted = TRUE; + + return(TRUE); +} + +/**********************************************************************//** +Flags an index corrupted both in the data dictionary cache +and in the SYS_INDEXES */ +UNIV_INTERN +void +dict_set_corrupted( +/*===============*/ + dict_index_t* index) /*!< in/out: index */ +{ + mem_heap_t* heap; + mtr_t mtr; + dict_index_t* sys_index; + dtuple_t* tuple; + dfield_t* dfield; + byte* buf; + const char* status; + btr_cur_t cursor; + + ut_ad(index); + ut_ad(mutex_own(&dict_sys->mutex)); + ut_ad(!dict_table_is_comp(dict_sys->sys_tables)); + ut_ad(!dict_table_is_comp(dict_sys->sys_indexes)); + +#ifdef UNIV_SYNC_DEBUG + ut_ad(sync_thread_levels_empty_except_dict()); +#endif + + /* Mark the table as corrupted only if the clustered index + is corrupted */ + if (dict_index_is_clust(index)) { + index->table->corrupted = TRUE; + } + + if (UNIV_UNLIKELY(dict_index_is_corrupted(index))) { + /* The index was already flagged corrupted. */ + ut_ad(index->table->corrupted); + return; + } + + heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t) + + sizeof(que_fork_t) + sizeof(upd_node_t) + + sizeof(upd_t) + 12)); + mtr_start(&mtr); + index->type |= DICT_CORRUPT; + + sys_index = UT_LIST_GET_FIRST(dict_sys->sys_indexes->indexes); + + /* Find the index row in SYS_INDEXES */ + tuple = dtuple_create(heap, 2); + + dfield = dtuple_get_nth_field(tuple, 0); + buf = mem_heap_alloc(heap, 8); + mach_write_to_8(buf, index->table->id); + dfield_set_data(dfield, buf, 8); + + dfield = dtuple_get_nth_field(tuple, 1); + buf = mem_heap_alloc(heap, 8); + mach_write_to_8(buf, index->id); + dfield_set_data(dfield, buf, 8); + + dict_index_copy_types(tuple, sys_index, 2); + + btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE, + BTR_MODIFY_LEAF, + &cursor, 0, __FILE__, __LINE__, &mtr); + + if (cursor.up_match == dtuple_get_n_fields(tuple)) { + /* UPDATE SYS_INDEXES SET TYPE=index->type + WHERE TABLE_ID=index->table->id AND INDEX_ID=index->id */ + ulint len; + byte* field = rec_get_nth_field_old( + btr_cur_get_rec(&cursor), + DICT_SYS_INDEXES_TYPE_FIELD, &len); + if (len != 4) { + goto fail; + } + mlog_write_ulint(field, index->type, MLOG_4BYTES, &mtr); + status = " InnoDB: Flagged corruption of "; + } else { +fail: + status = " InnoDB: Unable to flag corruption of "; + } + + mtr_commit(&mtr); + mem_heap_free(heap); + + ut_print_timestamp(stderr); + fputs(status, stderr); + dict_index_name_print(stderr, NULL, index); + putc('\n', stderr); +} + +/**********************************************************************//** +Flags an index corrupted in the data dictionary cache only. This +is used mostly to mark a corrupted index when index's own dictionary +is corrupted, and we force to load such index for repair purpose */ +UNIV_INTERN +void +dict_set_corrupted_index_cache_only( +/*================================*/ + dict_index_t* index) /*!< in/out: index */ +{ + ut_ad(index); + ut_ad(mutex_own(&dict_sys->mutex)); + ut_ad(!dict_table_is_comp(dict_sys->sys_tables)); + ut_ad(!dict_table_is_comp(dict_sys->sys_indexes)); + + /* Mark the table as corrupted only if the clustered index + is corrupted */ + if (dict_index_is_clust(index)) { + index->table->corrupted = TRUE; + } + + index->type |= DICT_CORRUPT; +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index ab1fb16361e..60590aa6638 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -52,6 +52,11 @@ static const char* SYSTEM_TABLE_NAME[] = { "SYS_FOREIGN", "SYS_FOREIGN_COLS" }; + +/* If this flag is TRUE, then we will load the cluster index's (and tables') +metadata even if it is marked as "corrupted". */ +UNIV_INTERN my_bool srv_load_corrupted = FALSE; + /****************************************************************//** Compare the name of an index column. @return TRUE if the i'th column of index is 'name'. */ @@ -1324,6 +1329,9 @@ err_len: goto err_len; } type = mach_read_from_4(field); + if (UNIV_UNLIKELY(type & (~0 << DICT_IT_BITS))) { + return("unknown SYS_INDEXES.TYPE bits"); + } field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len); if (UNIV_UNLIKELY(len != 4)) { @@ -1423,16 +1431,47 @@ dict_load_indexes( goto next_rec; } else if (err_msg) { fprintf(stderr, "InnoDB: %s\n", err_msg); + if (ignore_err & DICT_ERR_IGNORE_CORRUPT) { + goto next_rec; + } error = DB_CORRUPTION; goto func_exit; } ut_ad(index); + /* Check whether the index is corrupted */ + if (dict_index_is_corrupted(index)) { + ut_print_timestamp(stderr); + fputs(" InnoDB: ", stderr); + dict_index_name_print(stderr, NULL, index); + fputs(" is corrupted\n", stderr); + + if (!srv_load_corrupted + && !(ignore_err & DICT_ERR_IGNORE_CORRUPT) + && dict_index_is_clust(index)) { + dict_mem_index_free(index); + + error = DB_INDEX_CORRUPT; + goto func_exit; + } else { + /* We will load the index if + 1) srv_load_corrupted is TRUE + 2) ignore_err is set with + DICT_ERR_IGNORE_CORRUPT + 3) if the index corrupted is a secondary + index */ + ut_print_timestamp(stderr); + fputs(" InnoDB: load corrupted index ", stderr); + dict_index_name_print(stderr, NULL, index); + putc('\n', stderr); + } + } + /* We check for unsupported types first, so that the subsequent checks are relevant for the supported types. */ - if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { - + if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE + | DICT_CORRUPT)) { fprintf(stderr, "InnoDB: Error: unknown type %lu" " of index %s of table %s\n", @@ -1453,9 +1492,13 @@ dict_load_indexes( /* If caller can tolerate this error, we will continue to load the index and let caller deal with this error. However - mark the index and table corrupted */ - index->corrupted = TRUE; - table->corrupted = TRUE; + mark the index and table corrupted. We + only need to mark such in the index + dictionary cache for such metadata corruption, + since we would always be able to set it + when loading the dictionary cache */ + dict_set_corrupted_index_cache_only(index); + fprintf(stderr, "InnoDB: Index is corrupt but forcing" " load into data dictionary\n"); @@ -1495,9 +1538,10 @@ corrupted: index->name, table->name); /* If the force recovery flag is set, and - if the failed index is not the primary index, we - will continue and open other indexes */ - if (srv_force_recovery + if the failed index is not the clustered index, + we will continue and open other indexes */ + if ((srv_force_recovery + || srv_load_corrupted) && !dict_index_is_clust(index)) { error = DB_SUCCESS; goto next_rec; @@ -1812,6 +1856,30 @@ err_exit: err = dict_load_indexes(table, heap, ignore_err); + if (err == DB_INDEX_CORRUPT) { + /* Refuse to load the table if the table has a corrupted + cluster index */ + if (!srv_load_corrupted) { + fprintf(stderr, "InnoDB: Error: Load table "); + ut_print_name(stderr, NULL, TRUE, table->name); + fprintf(stderr, " failed, the table has corrupted" + " clustered indexes. Turn on" + " 'innodb_force_load_corrupted'" + " to drop it\n"); + + dict_table_remove_from_cache(table); + table = NULL; + goto func_exit; + } else { + dict_index_t* clust_index; + clust_index = dict_table_get_first_index(table); + + if (dict_index_is_corrupted(clust_index)) { + table->corrupted = TRUE; + } + } + } + /* Initialize table foreign_child value. Its value could be changed when dict_load_foreigns() is called below */ table->fk_max_recusive_level = 0; @@ -1838,9 +1906,15 @@ err_exit: index = dict_table_get_first_index(table); if (!srv_force_recovery || !index - || !dict_index_is_clust(index)) { + || !dict_index_is_clust(index)) { dict_table_remove_from_cache(table); table = NULL; + } else if (dict_index_is_corrupted(index)) { + + /* It is possible we force to load a corrupted + clustered index if srv_load_corrupted is set. + Mark the table as corrupted in this case */ + table->corrupted = TRUE; } } #if 0 @@ -1867,6 +1941,7 @@ err_exit: mutex_exit(&dict_foreign_err_mutex); } #endif /* 0 */ +func_exit: mem_heap_free(heap); return(table); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f8e96d5fa60..e5d714fc95f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1043,6 +1043,8 @@ convert_error_code_to_mysql( #endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ case DB_UNSUPPORTED: return(HA_ERR_UNSUPPORTED); + case DB_INDEX_CORRUPT: + return(HA_ERR_INDEX_CORRUPT); } } @@ -2078,6 +2080,27 @@ no_db_name: } +/*****************************************************************//** +A wrapper function of innobase_convert_name(), convert a table or +index name to the MySQL system_charset_info (UTF-8) and quote it if needed. +@return pointer to the end of buf */ +static inline +void +innobase_format_name( +/*==================*/ + char* buf, /*!< out: buffer for converted identifier */ + ulint buflen, /*!< in: length of buf, in bytes */ + const char* name, /*!< in: index or table name to format */ + ibool is_index_name) /*!< in: index name */ +{ + const char* bufend; + + bufend = innobase_convert_name(buf, buflen, name, strlen(name), + NULL, is_index_name); + + buf[bufend - buf] = '\0'; +} + /**********************************************************************//** Determines if the currently running transaction has been interrupted. @return TRUE if interrupted */ @@ -5664,12 +5687,14 @@ ha_innobase::index_read( index = prebuilt->index; - if (UNIV_UNLIKELY(index == NULL)) { + if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) { prebuilt->index_usable = FALSE; DBUG_RETURN(HA_ERR_CRASHED); } if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + DBUG_RETURN(dict_index_is_corrupted(index) + ? HA_ERR_INDEX_CORRUPT + : HA_ERR_TABLE_DEF_CHANGED); } /* Note that if the index for which the search template is built is not @@ -5855,10 +5880,33 @@ ha_innobase::change_active_index( prebuilt->index); if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - push_warning_printf(user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - HA_ERR_TABLE_DEF_CHANGED, - "InnoDB: insufficient history for index %u", - keynr); + if (dict_index_is_corrupted(prebuilt->index)) { + char index_name[MAX_FULL_NAME_LEN + 1]; + char table_name[MAX_FULL_NAME_LEN + 1]; + + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + + innobase_format_name( + table_name, sizeof table_name, + prebuilt->index->table->name, FALSE); + + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_INDEX_CORRUPT, + "InnoDB: Index %s for table %s is" + " marked as corrupted", + index_name, table_name); + DBUG_RETURN(1); + } else { + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: insufficient history for index %u", + keynr); + } + /* The caller seems to ignore this. Thus, we must check this again in row_search_for_mysql(). */ DBUG_RETURN(2); @@ -7518,6 +7566,10 @@ ha_innobase::records_in_range( n_rows = HA_POS_ERROR; goto func_exit; } + if (dict_index_is_corrupted(index)) { + n_rows = HA_ERR_INDEX_CORRUPT; + goto func_exit; + } if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) { n_rows = HA_ERR_TABLE_DEF_CHANGED; goto func_exit; @@ -8184,6 +8236,7 @@ ha_innobase::check( ulint n_rows_in_table = ULINT_UNDEFINED; ibool is_ok = TRUE; ulint old_isolation_level; + ibool table_corrupted; DBUG_ENTER("ha_innobase::check"); DBUG_ASSERT(thd == ha_thd()); @@ -8225,6 +8278,14 @@ ha_innobase::check( prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ; + /* Check whether the table is already marked as corrupted + before running the check table */ + table_corrupted = prebuilt->table->corrupted; + + /* Reset table->corrupted bit so that check table can proceed to + do additional check */ + prebuilt->table->corrupted = FALSE; + /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ mutex_enter(&kernel_mutex); srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ @@ -8233,6 +8294,7 @@ ha_innobase::check( for (index = dict_table_get_first_index(prebuilt->table); index != NULL; index = dict_table_get_next_index(index)) { + char index_name[MAX_FULL_NAME_LEN + 1]; #if 0 fputs("Validating index ", stderr); ut_print_name(stderr, trx, FALSE, index->name); @@ -8241,11 +8303,16 @@ ha_innobase::check( if (!btr_validate_index(index, prebuilt->trx)) { is_ok = FALSE; + + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NOT_KEYFILE, "InnoDB: The B-tree of" - " index '%-.200s' is corrupted.", - index->name); + " index %s is corrupted.", + index_name); continue; } @@ -8258,11 +8325,26 @@ ha_innobase::check( prebuilt->trx, prebuilt->index); if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - HA_ERR_TABLE_DEF_CHANGED, - "InnoDB: Insufficient history for" - " index '%-.200s'", - index->name); + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + + if (dict_index_is_corrupted(prebuilt->index)) { + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_INDEX_CORRUPT, + "InnoDB: Index %s is marked as" + " corrupted", + index_name); + is_ok = FALSE; + } else { + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: Insufficient history for" + " index %s", + index_name); + } continue; } @@ -8276,12 +8358,19 @@ ha_innobase::check( prebuilt->select_lock_type = LOCK_NONE; if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) { + innobase_format_name( + index_name, sizeof index_name, + index->name, TRUE); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NOT_KEYFILE, "InnoDB: The B-tree of" - " index '%-.200s' is corrupted.", - index->name); + " index %s is corrupted.", + index_name); is_ok = FALSE; + row_mysql_lock_data_dictionary(prebuilt->trx); + dict_set_corrupted(index); + row_mysql_unlock_data_dictionary(prebuilt->trx); } if (thd_killed(user_thd)) { @@ -8308,6 +8397,20 @@ ha_innobase::check( } } + if (table_corrupted) { + /* If some previous operation has marked the table as + corrupted in memory, and has not propagated such to + clustered index, we will do so here */ + index = dict_table_get_first_index(prebuilt->table); + + if (!dict_index_is_corrupted(index)) { + mutex_enter(&dict_sys->mutex); + dict_set_corrupted(index); + mutex_exit(&dict_sys->mutex); + } + prebuilt->table->corrupted = TRUE; + } + /* Restore the original isolation level */ prebuilt->trx->isolation_level = old_isolation_level; @@ -11101,6 +11204,11 @@ static MYSQL_SYSVAR_BOOL(large_prefix, innobase_large_prefix, "Support large index prefix length of REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes.", NULL, NULL, FALSE); +static MYSQL_SYSVAR_BOOL(force_load_corrupted, srv_load_corrupted, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Force InnoDB to load metadata of corrupted table.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, "Force InnoDB to not use next-key locking, to use only row-level locking.", @@ -11360,6 +11468,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(flush_method), MYSQL_SYSVAR(force_recovery), MYSQL_SYSVAR(large_prefix), + MYSQL_SYSVAR(force_load_corrupted), MYSQL_SYSVAR(locks_unsafe_for_binlog), MYSQL_SYSVAR(lock_wait_timeout), #ifdef UNIV_LOG_ARCHIVE diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 74ef2d2dab7..eb40621abbe 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -203,6 +203,17 @@ void buf_LRU_stat_update(void); /*=====================*/ +/******************************************************************//** +Remove one page from LRU list and put it to free list */ +UNIV_INTERN +void +buf_LRU_free_one_page( +/*==================*/ + buf_page_t* bpage) /*!< in/out: block, must contain a file page and + be in a state where it can be freed; there + may or may not be a hash index to the page */ + __attribute__((nonnull)); + #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /**********************************************************************//** Validates the LRU list. diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 28ef64500cc..415470b61b4 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -110,6 +110,7 @@ enum db_err { foreign keys as its prefix columns */ DB_TOO_BIG_INDEX_COL, /* index column size exceeds maximum limit */ + DB_INDEX_CORRUPT, /* we have corrupted index */ /* The following are partial failure codes */ DB_FAIL = 1000, diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 22df826da65..5d136862bc6 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -137,8 +137,10 @@ dict_create(void); header is created */ /*-------------------------------------------------------------*/ -/* The field number of the page number field in the sys_indexes table -clustered index */ +/* The field numbers in the SYS_TABLES clustered index */ +#define DICT_SYS_TABLES_TYPE_FIELD 5 + +/* The field numbers in the SYS_INDEXES clustered index */ #define DICT_SYS_INDEXES_PAGE_NO_FIELD 8 #define DICT_SYS_INDEXES_SPACE_NO_FIELD 7 #define DICT_SYS_INDEXES_TYPE_FIELD 6 diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index f979d0fcc96..93e9162dc87 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -585,6 +585,20 @@ dict_table_get_next_index( # define dict_table_get_next_index(index) UT_LIST_GET_NEXT(indexes, index) #endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ + +/* Skip corrupted index */ +#define dict_table_skip_corrupt_index(index) \ + while (index && dict_index_is_corrupted(index)) { \ + index = dict_table_get_next_index(index); \ + } + +/* Get the next non-corrupt index */ +#define dict_table_next_uncorrupted_index(index) \ +do { \ + index = dict_table_get_next_index(index); \ + dict_table_skip_corrupt_index(index); \ +} while (0) + /********************************************************************//** Check whether the index is the clustered index. @return nonzero for clustered index, zero for other indexes */ @@ -593,7 +607,7 @@ ulint dict_index_is_clust( /*================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is unique. @return nonzero for unique index, zero for other indexes */ @@ -602,7 +616,7 @@ ulint dict_index_is_unique( /*=================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ @@ -611,7 +625,7 @@ ulint dict_index_is_ibuf( /*===============*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is a secondary index or the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ @@ -620,7 +634,7 @@ ulint dict_index_is_sec_or_ibuf( /*======================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of user-defined columns in a table in the dictionary @@ -630,7 +644,8 @@ UNIV_INLINE ulint dict_table_get_n_user_cols( /*=======================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of system columns in a table in the dictionary cache. @return number of system (e.g., ROW_ID) columns of a table */ @@ -638,7 +653,8 @@ UNIV_INLINE ulint dict_table_get_n_sys_cols( /*======================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of all columns (also system) in a table in the dictionary cache. @@ -647,7 +663,8 @@ UNIV_INLINE ulint dict_table_get_n_cols( /*==================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); #ifdef UNIV_DEBUG /********************************************************************//** Gets the nth column of a table. @@ -1243,6 +1260,56 @@ void dict_close(void); /*============*/ +/**********************************************************************//** +Check whether the table is corrupted. +@return nonzero for corrupted table, zero for valid tables */ +UNIV_INLINE +ulint +dict_table_is_corrupted( +/*====================*/ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); + +/**********************************************************************//** +Check whether the index is corrupted. +@return nonzero for corrupted index, zero for valid indexes */ +UNIV_INLINE +ulint +dict_index_is_corrupted( +/*====================*/ + const dict_index_t* index) /*!< in: index */ + __attribute__((nonnull, pure, warn_unused_result)); + +/**********************************************************************//** +Flags an index and table corrupted both in the data dictionary cache +and in the system table SYS_INDEXES. */ +UNIV_INTERN +void +dict_set_corrupted( +/*===============*/ + dict_index_t* index) /*!< in/out: index */ + UNIV_COLD __attribute__((nonnull)); + +/**********************************************************************//** +Flags an index corrupted in the data dictionary cache only. This +is used mostly to mark a corrupted index when index's own dictionary +is corrupted, and we force to load such index for repair purpose */ +UNIV_INTERN +void +dict_set_corrupted_index_cache_only( +/*================================*/ + dict_index_t* index); /*!< in/out: index */ + +/**********************************************************************//** +Flags a table with specified space_id corrupted in the table dictionary +cache. +@return TRUE if successful */ +UNIV_INTERN +ibool +dict_set_corrupted_by_space( +/*========================*/ + ulint space_id); /*!< in: space ID */ + #ifndef UNIV_NONINL #include "dict0dict.ic" #endif diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 59811568556..ade9e627e29 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -27,6 +27,7 @@ Created 1/8/1996 Heikki Tuuri #ifndef UNIV_HOTBACKUP #include "dict0load.h" #include "rem0types.h" +#include "srv0srv.h" /*********************************************************************//** Gets the minimum number of bytes per character. @@ -828,7 +829,7 @@ dict_table_check_if_in_cache_low( } /**********************************************************************//** -load a table into dictionary cache, ignore any error specified during load; +load a table into dictionary cache, ignore any error specified during load; @return table, NULL if not found */ UNIV_INLINE dict_table_t* @@ -872,6 +873,18 @@ dict_table_get_low( table = dict_table_check_if_in_cache_low(table_name); + if (table && table->corrupted) { + fprintf(stderr, "InnoDB: table"); + ut_print_name(stderr, NULL, TRUE, table->name); + if (srv_load_corrupted) { + fputs(" is corrupted, but" + " innodb_force_load_corrupted is set\n", stderr); + } else { + fputs(" is corrupted\n", stderr); + return(NULL); + } + } + if (table == NULL) { table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE); } @@ -937,4 +950,35 @@ dict_max_field_len_store_undo( return(prefix_len); } +/********************************************************************//** +Check whether the table is corrupted. +@return nonzero for corrupted table, zero for valid tables */ +UNIV_INLINE +ulint +dict_table_is_corrupted( +/*====================*/ + const dict_table_t* table) /*!< in: table */ +{ + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + return(UNIV_UNLIKELY(table->corrupted)); +} + +/********************************************************************//** +Check whether the index is corrupted. +@return nonzero for corrupted index, zero for valid indexes */ +UNIV_INLINE +ulint +dict_index_is_corrupted( +/*====================*/ + const dict_index_t* index) /*!< in: index */ +{ + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + return(UNIV_UNLIKELY((index->type & DICT_CORRUPT) + || (index->table && index->table->corrupted))); +} + #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 3a475fa85fc..9ded0dba39b 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -51,7 +51,12 @@ combination of types */ #define DICT_UNIQUE 2 /*!< unique index */ #define DICT_UNIVERSAL 4 /*!< index which can contain records from any other index */ -#define DICT_IBUF 8 /*!< insert buffer tree */ +#define DICT_IBUF 8 /*!< insert buffer tree */ +#define DICT_CORRUPT 16 /*!< bit to store the corrupted flag + in SYS_INDEXES.TYPE */ + +#define DICT_IT_BITS 5 /*!< number of bits used for + SYS_INDEXES.TYPE */ /* @} */ /** Types for a table object */ @@ -369,8 +374,9 @@ struct dict_index_struct{ /*!< space where the index tree is placed */ unsigned page:32;/*!< index tree root page number */ #endif /* !UNIV_HOTBACKUP */ - unsigned type:4; /*!< index type (DICT_CLUSTERED, DICT_UNIQUE, - DICT_UNIVERSAL, DICT_IBUF) */ + unsigned type:DICT_IT_BITS; + /*!< index type (DICT_CLUSTERED, DICT_UNIQUE, + DICT_UNIVERSAL, DICT_IBUF, DICT_CORRUPT) */ unsigned trx_id_offset:10;/*!< position of the trx id column in a clustered index record, if the fields before it are known to be of a fixed size, @@ -391,8 +397,6 @@ struct dict_index_struct{ /*!< TRUE if this index is marked to be dropped in ha_innobase::prepare_drop_index(), otherwise FALSE */ - unsigned corrupted:1; - /*!< TRUE if the index object is corrupted */ dict_field_t* fields; /*!< array of field descriptions */ #ifndef UNIV_HOTBACKUP UT_LIST_NODE_T(dict_index_t) diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 8cbd7cd5783..f0a05a38070 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -51,7 +51,8 @@ be or-ed together */ enum dict_err_ignore { DICT_ERR_IGNORE_NONE = 0, /*!< no error to ignore */ DICT_ERR_IGNORE_INDEX_ROOT = 1, /*!< ignore error if index root - page is FIL_NUL or incorrect value */ + page is FIL_NULL or incorrect value */ + DICT_ERR_IGNORE_CORRUPT = 2, /*!< skip corrupted indexes */ DICT_ERR_IGNORE_ALL = 0xFFFF /*!< ignore all errors */ }; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 7a93548cb03..dfe7397d189 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -141,6 +141,10 @@ extern ulint srv_log_buffer_size; extern ulong srv_flush_log_at_trx_commit; extern char srv_adaptive_flushing; +/* If this flag is TRUE, then we will load the indexes' (and tables') metadata +even if they are marked as "corrupted". Mostly it is for DBA to process +corrupted index and table */ +extern my_bool srv_load_corrupted; /* The sort order table of the MySQL latin1_swedish_ci character set collation */ diff --git a/storage/innobase/pars/pars0opt.c b/storage/innobase/pars/pars0opt.c index 2e392ba4836..d992805d9ef 100644 --- a/storage/innobase/pars/pars0opt.c +++ b/storage/innobase/pars/pars0opt.c @@ -568,7 +568,7 @@ opt_search_plan_for_table( best_last_op = last_op; } - index = dict_table_get_next_index(index); + dict_table_next_uncorrupted_index(index); } plan->index = best_index; diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 715e376f8f9..62146a95f11 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -118,6 +118,9 @@ ins_node_create_entry_list( node->entry_sys_heap); UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry); + /* We will include all indexes (include those corrupted + secondary indexes) in the entry list. Filteration of + these corrupted index will be done in row_ins() */ index = dict_table_get_next_index(index); } } @@ -2046,7 +2049,6 @@ row_ins_index_entry_low( mtr_start(&mtr); if (err != DB_SUCCESS) { - goto function_exit; } @@ -2431,6 +2433,13 @@ row_ins( node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); + + /* Skip corrupted secondar index and its entry */ + while (node->index && dict_index_is_corrupted(node->index)) { + + node->index = dict_table_get_next_index(node->index); + node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); + } } ut_ad(node->entry == NULL); diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 5be437add5a..d42f21241ca 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -2554,8 +2554,9 @@ row_merge_is_index_usable( const trx_t* trx, /*!< in: transaction */ const dict_index_t* index) /*!< in: index to check */ { - return(!trx->read_view - || read_view_sees_trx_id(trx->read_view, index->trx_id)); + return(!dict_index_is_corrupted(index) + && (!trx->read_view + || read_view_sees_trx_id(trx->read_view, index->trx_id))); } /*********************************************************************//** diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index a56d419d1f0..d98d47a5da6 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -3098,7 +3098,8 @@ row_drop_table_for_mysql( ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - table = dict_table_get_low_ignore_err(name, DICT_ERR_IGNORE_INDEX_ROOT); + table = dict_table_get_low_ignore_err( + name, DICT_ERR_IGNORE_INDEX_ROOT | DICT_ERR_IGNORE_CORRUPT); if (!table) { err = DB_TABLE_NOT_FOUND; diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index 83e7c9e4857..c008c2d1c31 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -469,6 +469,13 @@ row_purge_del_mark( heap = mem_heap_create(1024); while (node->index != NULL) { + /* skip corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; /* Build the index entry */ @@ -516,6 +523,12 @@ row_purge_upd_exist_or_extern_func( heap = mem_heap_create(1024); while (node->index != NULL) { + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; if (row_upd_changes_ord_field_binary(node->index, node->update, diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 36da621e077..a1039010d00 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -3441,6 +3441,13 @@ row_search_for_mysql( return(DB_MISSING_HISTORY); } + if (dict_index_is_corrupted(index)) { +#ifdef UNIV_SYNC_DEBUG + ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); +#endif /* UNIV_SYNC_DEBUG */ + return(DB_CORRUPTION); + } + if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" diff --git a/storage/innobase/row/row0uins.c b/storage/innobase/row/row0uins.c index d25afed3840..4fa97c9355d 100644 --- a/storage/innobase/row/row0uins.c +++ b/storage/innobase/row/row0uins.c @@ -328,6 +328,8 @@ row_undo_ins( node->index = dict_table_get_next_index( dict_table_get_first_index(node->table)); + dict_table_skip_corrupt_index(node->index); + while (node->index != NULL) { dtuple_t* entry; ulint err; @@ -355,7 +357,7 @@ row_undo_ins( } } - node->index = dict_table_get_next_index(node->index); + dict_table_next_uncorrupted_index(node->index); } log_free_check(); diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 2188fdeff49..b86ce9eeabd 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -573,6 +573,14 @@ row_undo_mod_upd_del_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; entry = row_build_index_entry(node->row, node->ext, @@ -626,6 +634,13 @@ row_undo_mod_del_mark_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; entry = row_build_index_entry(node->row, node->ext, @@ -677,6 +692,13 @@ row_undo_mod_upd_exist_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; if (row_upd_changes_ord_field_binary(node->index, node->update, @@ -859,6 +881,9 @@ row_undo_mod( node->index = dict_table_get_next_index( dict_table_get_first_index(node->table)); + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + if (node->rec_type == TRX_UNDO_UPD_EXIST_REC) { err = row_undo_mod_upd_exist_sec(node, thr); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index a2f6c17413f..6559c529117 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -2320,6 +2320,13 @@ row_upd( while (node->index != NULL) { + /* Skip corrupted index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + log_free_check(); err = row_upd_sec_step(node, thr); diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 1ef1a082bb2..bd009f1fd32 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -712,6 +712,8 @@ ut_strerr( return("No index on referencing keys in referencing table"); case DB_PARENT_NO_INDEX: return("No index on referenced keys in referenced table"); + case DB_INDEX_CORRUPT: + return("Index corrupted"); case DB_END_OF_INDEX: return("End of index"); /* do not add default: in order to produce a warning if new code From 7abcb1dd087b5ba342f94444d57ac34cdd9bcc27 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Tue, 16 Aug 2011 20:51:40 -0700 Subject: [PATCH 038/143] Add two tests for "innodb_large_prefix" and "innodb_force_load_corrupted" in sys_vars test suite. --- .../suite/innodb/t/innodb_corrupt_bit.test | 15 --- mysql-test/suite/sys_vars/r/all_vars.result | 4 - .../innodb_force_load_corrupted_basic.result | 53 +++++++++ .../r/innodb_large_prefix_basic.result | 92 ++++++++++++++++ .../t/innodb_force_load_corrupted_basic.test | 102 ++++++++++++++++++ .../sys_vars/t/innodb_large_prefix_basic.test | 70 ++++++++++++ storage/innobase/buf/buf0buf.c | 2 - 7 files changed, 317 insertions(+), 21 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result create mode 100644 mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test create mode 100644 mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test diff --git a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test index 7d98a8e4a03..34991362f98 100644 --- a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test +++ b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test @@ -102,23 +102,8 @@ drop index idxā on corrupt_bit_test_ā; check table corrupt_bit_test_ā; -# Shut down the server --- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server 20 --- source include/wait_until_disconnected.inc - -# Restart the server --- disable_query_log ---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---enable_reconnect ---source include/wait_until_connected_again.inc ---disable_reconnect --- enable_query_log - set names utf8; -# The index is marked as suspect in Sys_indexes too, so after server -# reboot, the attempt to use the index will fail too. -- error ER_NOT_KEYFILE select z from corrupt_bit_test_ā; diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index edd6f57e32d..af05e3bc393 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,9 +11,5 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: -INNODB_FORCE_LOAD_CORRUPTED -INNODB_LARGE_PREFIX -INNODB_FORCE_LOAD_CORRUPTED -INNODB_LARGE_PREFIX drop table t1; drop table t2; diff --git a/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result b/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result new file mode 100644 index 00000000000..bc9b7019eb8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_031_01----------------------#' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +'#---------------------BS_STVARS_031_02----------------------#' +SET @@GLOBAL.innodb_force_load_corrupted=1; +ERROR HY000: Variable 'innodb_force_load_corrupted' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +'#---------------------BS_STVARS_031_03----------------------#' +SELECT IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_031_04----------------------#' +SELECT @@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted; +@@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted +1 +1 Expected +'#---------------------BS_STVARS_031_05----------------------#' +SELECT COUNT(@@innodb_force_load_corrupted); +COUNT(@@innodb_force_load_corrupted) +1 +1 Expected +SELECT COUNT(@@local.innodb_force_load_corrupted); +ERROR HY000: Variable 'innodb_force_load_corrupted' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_force_load_corrupted); +ERROR HY000: Variable 'innodb_force_load_corrupted' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +SELECT innodb_force_load_corrupted = @@SESSION.innodb_force_load_corrupted; +ERROR 42S22: Unknown column 'innodb_force_load_corrupted' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result b/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result new file mode 100644 index 00000000000..adb56b347cd --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result @@ -0,0 +1,92 @@ +SET @start_global_value = @@global.innodb_large_prefix; +SELECT @start_global_value; +@start_global_value +0 +Valid values are 'ON' and 'OFF' +select @@global.innodb_large_prefix in (0, 1); +@@global.innodb_large_prefix in (0, 1) +1 +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select @@session.innodb_large_prefix; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable +show global variables like 'innodb_large_prefix'; +Variable_name Value +innodb_large_prefix OFF +show session variables like 'innodb_large_prefix'; +Variable_name Value +innodb_large_prefix OFF +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set global innodb_large_prefix='OFF'; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set @@global.innodb_large_prefix=1; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set global innodb_large_prefix=0; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set @@global.innodb_large_prefix='ON'; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set session innodb_large_prefix='OFF'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +set @@session.innodb_large_prefix='ON'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +set global innodb_large_prefix=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_large_prefix' +set global innodb_large_prefix=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_large_prefix' +set global innodb_large_prefix=2; +ERROR 42000: Variable 'innodb_large_prefix' can't be set to the value of '2' +NOTE: The following should fail with ER_WRONG_VALUE_FOR_VAR (BUG#50643) +set global innodb_large_prefix=-3; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set global innodb_large_prefix='AUTO'; +ERROR 42000: Variable 'innodb_large_prefix' can't be set to the value of 'AUTO' +SET @@global.innodb_large_prefix = @start_global_value; +SELECT @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 diff --git a/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test b/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test new file mode 100644 index 00000000000..1726b320f47 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test @@ -0,0 +1,102 @@ + + +################## mysql-test\t\innodb_force_load_corrupted_basic.test ##### +# # +# Variable Name: innodb_force_load_corrupted # +# Scope: Global # +# Access Type: Static # +# Data Type: boolean # +# # +# # +# Creation Date: 2008-02-07 # +# Author : Sharique Abdullah # +# # +# # +# Description:Test Cases of Dynamic System Variable innodb_force_load_corrupted# +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc + +--echo '#---------------------BS_STVARS_031_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_031_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_force_load_corrupted=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_031_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_031_04----------------------#' +################################################################################ +# Check if accessing variable with and without GLOBAL point to same variable # +################################################################################ +SELECT @@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_031_05----------------------#' +################################################################################ +# Check if innodb_force_load_corrupted can be accessed with and without @@ sign # +################################################################################ + +SELECT COUNT(@@innodb_force_load_corrupted); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_force_load_corrupted); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_force_load_corrupted); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_force_load_corrupted = @@SESSION.innodb_force_load_corrupted; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test b/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test new file mode 100644 index 00000000000..582e9ffbee8 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test @@ -0,0 +1,70 @@ + + +# 2010-01-25 - Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_large_prefix; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'ON' and 'OFF' +select @@global.innodb_large_prefix in (0, 1); +select @@global.innodb_large_prefix; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.innodb_large_prefix; +show global variables like 'innodb_large_prefix'; +show session variables like 'innodb_large_prefix'; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; + +# +# show that it's writable +# +set global innodb_large_prefix='OFF'; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set @@global.innodb_large_prefix=1; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set global innodb_large_prefix=0; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set @@global.innodb_large_prefix='ON'; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +--error ER_GLOBAL_VARIABLE +set session innodb_large_prefix='OFF'; +--error ER_GLOBAL_VARIABLE +set @@session.innodb_large_prefix='ON'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_large_prefix=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_large_prefix=1e1; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_large_prefix=2; +--echo NOTE: The following should fail with ER_WRONG_VALUE_FOR_VAR (BUG#50643) +set global innodb_large_prefix=-3; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_large_prefix='AUTO'; + +# +# Cleanup +# + +SET @@global.innodb_large_prefix = @start_global_value; +SELECT @@global.innodb_large_prefix; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 565fbe7bbf4..7bbe4f3b0c6 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3487,7 +3487,6 @@ buf_mark_space_corrupt( const ibool uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); ulint space = bpage->space; - ulint offset = bpage->offset; ibool ret = TRUE; /* First unfix and release lock on the bpage */ @@ -3507,7 +3506,6 @@ buf_mark_space_corrupt( /* Find the table with specified space id, and mark it corrupted */ if (dict_set_corrupted_by_space(space)) { - ut_ad(bpage->space == space && bpage->offset == offset); buf_LRU_free_one_page(bpage); } else { ret = FALSE; From d9c3d35437286eac641d1e110f4a5dfe160eb60a Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Wed, 17 Aug 2011 02:39:55 -0700 Subject: [PATCH 039/143] In innobase_format_name() we should call innobase_convert_name() with "!is_index_name" instead of "is_index_name", so the table name in the error message would not be formated as index name. --- mysql-test/suite/innodb/r/innodb_corrupt_bit.result | 2 +- storage/innobase/handler/ha_innodb.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result index 4253adc93aa..c88e1ed2504 100644 --- a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result +++ b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result @@ -45,7 +45,7 @@ select z from corrupt_bit_test_ā; ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it show warnings; Level Code Message -Warning 179 InnoDB: Index "idxē" for table "test/corrupt_bit_test_@1s" is marked as corrupted +Warning 179 InnoDB: Index "idxē" for table "test"."corrupt_bit_test_ā" is marked as corrupted Error 1034 Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); select * from corrupt_bit_test_ā use index(primary) where a = 10001; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e5d714fc95f..c4283d65a2a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2096,7 +2096,9 @@ innobase_format_name( const char* bufend; bufend = innobase_convert_name(buf, buflen, name, strlen(name), - NULL, is_index_name); + NULL, !is_index_name); + + ut_ad((ulint) (bufend - buf) < buflen); buf[bufend - buf] = '\0'; } From 704e51644a428611c9a0993eac81c0bbf4d394f9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 17 Aug 2011 14:42:18 +0200 Subject: [PATCH 040/143] Bug #11766654 59811: RE-INSTATE PROCEDURE MTR.FORCE_RESTART IN MTR, REMOVED BY 49978 Just put it back in where it was. --- mysql-test/include/mtr_check.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index 55e346c2007..699a35a1831 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -72,3 +72,13 @@ BEGIN mysql.user; END|| + +-- +-- Procedure used by test case used to force all +-- servers to restart after testcase and thus skipping +-- check test case after test +-- +CREATE DEFINER=root@localhost PROCEDURE force_restart() +BEGIN + SELECT 1 INTO OUTFILE 'force_restart'; +END|| From a8ee6e48f7129d35a2d83beab26f920e01092032 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 18 Aug 2011 10:38:51 +0400 Subject: [PATCH 041/143] BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD CRASHES SERVER Flushing of MERGE table or one of its child tables, which was locked by flushing thread using LOCK TABLES, might have caused crashes or assertion failures if the thread failed to reopen child or parent table. Particularly, this might have happened when another connection killed this FLUSH TABLE statement/connection. Also this problem might have occurred when we failed to reopen MERGE table or one of its children when executing DDL statement under LOCK TABLES. The problem was caused by the fact that reopen_tables() might have failed to reopen child table but still tried to reopen, reattach children for and re-lock its parent. Vice versa it might have failed to reopen parent but kept references from children to parent around. Since reopen_tables() closes table it has failed to reopen and therefore frees all associated memory such dangling references led to crashes when followed. This patch solves this problem by ensuring that we always close parent table and all its children if we fail to reopen this table or one of its children. Same happens if we fail to reattach children to parent. Affects 5.1 only. mysql-test/r/merge.result: A test case for BUG#11763712. mysql-test/t/merge.test: A test case for BUG#11763712. sql/sql_base.cc: When flushing tables under LOCK TABLES, all locked and flushed tables are released and then reopened. It may happen that we failed to reopen some tables, in this case we reopen as much tables as possible. If it was not possible to reopen MERGE child, MERGE parent is unusable and must be removed from thread open tables list. If it was not possible to reopen MERGE parent, all MERGE child table objects are unusable as well, at least because their locks are handled by MERGE parent. They must also be removed from thread open tables list. In other words if it was impossible to reopen any object of a MERGE table or reattach child tables, all objects of this MERGE table must be considered unusable and closed. --- mysql-test/r/merge.result | 29 ++++++ mysql-test/t/merge.test | 45 ++++++++++ sql/sql_base.cc | 183 +++++++++++++++++++++++++++++--------- 3 files changed, 215 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 3af152672ab..a4f1c79dff4 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2341,4 +2341,33 @@ REPAIR TABLE m1; Table Op Msg_type Msg_text test.m1 repair note The storage engine for the table doesn't support repair DROP TABLE m1, t1; +# +# BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +# CRASHES SERVER +# +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE t3(a INT, b INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); +# Test reopen merge parent failure +LOCK TABLES m1 READ; +# Remove 'm1' table using file operations. +FLUSH TABLES; +ERROR 42S02: Table 'test.m1' doesn't exist +UNLOCK TABLES; +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); +# Test reopen merge child failure +LOCK TABLES m1 READ; +# Remove 't1' table using file operations. +FLUSH TABLES; +ERROR 42S02: Table 'test.t1' doesn't exist +UNLOCK TABLES; +CREATE TABLE t1(a INT); +# Test reattach merge failure +LOCK TABLES m1 READ; +# Replace 't1' with 't3' table using file operations. +FLUSH TABLES; +ERROR HY000: Can't reopen table: 'm1' +UNLOCK TABLES; +DROP TABLE t1, t2, t3, m1; End of 5.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index f290803bbd2..a6affbb0540 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1783,4 +1783,49 @@ REPAIR TABLE m1; # DROP TABLE m1, t1; + +--echo # +--echo # BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +--echo # CRASHES SERVER +--echo # +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE t3(a INT, b INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); + +--echo # Test reopen merge parent failure +LOCK TABLES m1 READ; +--echo # Remove 'm1' table using file operations. +remove_file $MYSQLD_DATADIR/test/m1.MRG; +remove_file $MYSQLD_DATADIR/test/m1.frm; +--error ER_NO_SUCH_TABLE +FLUSH TABLES; +UNLOCK TABLES; +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); + +--echo # Test reopen merge child failure +LOCK TABLES m1 READ; +--echo # Remove 't1' table using file operations. +remove_file $MYSQLD_DATADIR/test/t1.frm; +remove_file $MYSQLD_DATADIR/test/t1.MYI; +remove_file $MYSQLD_DATADIR/test/t1.MYD; +--error ER_NO_SUCH_TABLE +FLUSH TABLES; +UNLOCK TABLES; +CREATE TABLE t1(a INT); + +--echo # Test reattach merge failure +LOCK TABLES m1 READ; +--echo # Replace 't1' with 't3' table using file operations. +remove_file $MYSQLD_DATADIR/test/t1.frm; +remove_file $MYSQLD_DATADIR/test/t1.MYI; +remove_file $MYSQLD_DATADIR/test/t1.MYD; +copy_file $MYSQLD_DATADIR/test/t3.frm $MYSQLD_DATADIR/test/t1.frm; +copy_file $MYSQLD_DATADIR/test/t3.MYI $MYSQLD_DATADIR/test/t1.MYI; +copy_file $MYSQLD_DATADIR/test/t3.MYD $MYSQLD_DATADIR/test/t1.MYD; +--error ER_CANT_REOPEN_TABLE +FLUSH TABLES; +UNLOCK TABLES; +DROP TABLE t1, t2, t3, m1; + --echo End of 5.1 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index dc78f3b84c6..971a54d88c2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -96,6 +96,13 @@ static TABLE_SHARE *oldest_unused_share, end_of_unused_share; static pthread_mutex_t LOCK_table_share; static bool table_def_inited= 0; +/** + Dummy TABLE instance which is used in reopen_tables() and reattach_merge() + functions to mark MERGE tables and their children with which there is some + kind of problem and which therefore we need to close. +*/ +static TABLE bad_merge_marker; + static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list, const char *alias, char *cache_key, uint cache_key_length, @@ -3214,47 +3221,66 @@ void close_data_files_and_morph_locks(THD *thd, const char *db, } +/** + @brief Mark merge parent and children with bad_merge_marker + + @param[in,out] parent the TABLE object of the parent +*/ + +static void mark_merge_parent_and_children_as_bad(TABLE *parent) +{ + TABLE_LIST *child_l; + DBUG_ENTER("mark_merge_parent_and_children_as_bad"); + parent->parent= &bad_merge_marker; + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + child_l->table->parent= &bad_merge_marker; + child_l->table= NULL; + if (&child_l->next_global == parent->child_last_l) + break; + } + DBUG_VOID_RETURN; +} + + /** Reattach MERGE children after reopen. @param[in] thd thread context - @param[in,out] err_tables_p pointer to pointer of tables in error + + @note If reattach failed for certain MERGE table, the table (and all + it's children) are marked with bad_merge_marker. @return status - @retval FALSE OK, err_tables_p unchanged - @retval TRUE Error, err_tables_p contains table(s) + @retval FALSE OK + @retval TRUE Error */ -static bool reattach_merge(THD *thd, TABLE **err_tables_p) +static bool reattach_merge(THD *thd) { TABLE *table; - TABLE *next; - TABLE **prv_p= &thd->open_tables; bool error= FALSE; DBUG_ENTER("reattach_merge"); - for (table= thd->open_tables; table; table= next) + for (table= thd->open_tables; table; table= table->next) { - next= table->next; - DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx next: 0x%lx", + DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx", table->s->db.str, table->s->table_name.str, - (long) table, (long) next)); - /* Reattach children for MERGE tables with "closed data files" only. */ - if (table->child_l && !table->children_attached) + (long) table)); + /* + Reattach children only for MERGE tables that had children or parent + with "closed data files" and were reopen. For extra safety skip MERGE + tables which we failed to reopen (should not happen with current code). + */ + if (table->child_l && table->parent != &bad_merge_marker && + !table->children_attached) { DBUG_PRINT("tcache", ("MERGE parent, attach children")); - if(table->file->extra(HA_EXTRA_ATTACH_CHILDREN)) + if (table->file->extra(HA_EXTRA_ATTACH_CHILDREN)) { my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); error= TRUE; - /* Remove table from open_tables. */ - *prv_p= next; - if (next) - prv_p= &next->next; - /* Stack table on error list. */ - table->next= *err_tables_p; - *err_tables_p= table; - continue; + mark_merge_parent_and_children_as_bad(table); } else { @@ -3264,7 +3290,6 @@ static bool reattach_merge(THD *thd, TABLE **err_tables_p) table->s->table_name.str, (long) table)); } } - prv_p= &table->next; } DBUG_RETURN(error); } @@ -3294,7 +3319,6 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) { TABLE *table,*next,**prev; TABLE **tables,**tables_ptr; // For locks - TABLE *err_tables= NULL; bool error=0, not_used; bool merge_table_found= FALSE; const uint flags= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN | @@ -3328,29 +3352,69 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) for (table=thd->open_tables; table ; table=next) { uint db_stat=table->db_stat; + TABLE *parent= table->child_l ? table : table->parent; next=table->next; DBUG_PRINT("tcache", ("open table: '%s'.'%s' 0x%lx " "parent: 0x%lx db_stat: %u", table->s->db.str, table->s->table_name.str, (long) table, (long) table->parent, db_stat)); - if (table->child_l && !db_stat) + /* + If we need to reopen child or parent table in a MERGE table, then + children in this MERGE table has to be already detached at this + point. + */ + DBUG_ASSERT(db_stat || !parent || !parent->children_attached); + /* + Thanks to the above assumption the below condition will guarantee that + merge_table_found is TRUE when we need to reopen child or parent table. + Note that it works even in situation when it is only a child and not a + parent that needs reopen (this can happen when get_locks == FALSE). + */ + if (table->child_l && !table->children_attached) merge_table_found= TRUE; - if (!tables || (!db_stat && reopen_table(table))) + + if (!tables) { - my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); /* - If we could not allocate 'tables', we may close open tables - here. If a MERGE table is affected, detach the children first. - It is not necessary to clear the child or parent table reference - of this table because the TABLE is freed. But we need to clear - the child or parent references of the other belonging tables so - that they cannot be moved into the unused_tables chain with - these pointers set. + If we could not allocate 'tables' we close ALL open tables here. + Before closing MERGE child or parent we need to detach children + and/or clear references in/to them. */ - if (table->child_l || table->parent) + if (parent) detach_merge_children(table, TRUE); - VOID(hash_delete(&open_cache,(uchar*) table)); - error=1; + } + else if (table->parent == &bad_merge_marker) + { + /* + This is either a child or a parent of a MERGE table for which + we already decided that we are unable to reopen it. Close it. + + Reset parent reference, it may be used while freeing the table. + */ + table->parent= NULL; + } + else if (!db_stat && reopen_table(table)) + { + /* + If we fail to reopen a child or a parent in a MERGE table and the + MERGE table is affected for the first time, mark all relevant tables + invalid. Otherwise handle it as usual. + + All in all we must end up with: + - child tables are detached from parent. This was done earlier, + but child<->parent references were kept valid for reopen. + - parent is not in the to-be-locked tables + - all child tables and parent are not in the THD::open_tables. + - all child tables and parent are not in the open_cache. + + Please note that below we do additional pass through THD::open_tables + list to achieve the last three points. + */ + if (parent) + { + mark_merge_parent_and_children_as_bad(parent); + table->parent= NULL; + } } else { @@ -3366,21 +3430,56 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) table->s->version=0; table->open_placeholder= 0; } + continue; } + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + VOID(hash_delete(&open_cache, (uchar *) table)); + error= 1; } *prev=0; /* When all tables are open again, we can re-attach MERGE children to - their parents. All TABLE objects are still present. + their parents. + + If there was an error while reopening a child or a parent of a MERGE + table, or while reattaching child tables to their parents, some tables + may have been kept open but marked for close with bad_merge_marker. + Close these tables now. */ - DBUG_PRINT("tcache", ("re-attaching MERGE tables: %d", merge_table_found)); - if (!error && merge_table_found && reattach_merge(thd, &err_tables)) + if (tables && merge_table_found && (error|= reattach_merge(thd))) { - while (err_tables) + prev= &thd->open_tables; + for (table= thd->open_tables; table; table= next) { - VOID(hash_delete(&open_cache, (uchar*) err_tables)); - err_tables= err_tables->next; + next= table->next; + if (table->parent == &bad_merge_marker) + { + /* Remove merge parent from to-be-locked tables array. */ + if (get_locks && table->child_l) + { + TABLE **t; + for (t= tables; t < tables_ptr; t++) + { + if (*t == table) + { + tables_ptr--; + memmove(t, t + 1, (tables_ptr - t) * sizeof(TABLE *)); + break; + } + } + } + /* Reset parent reference, it may be used while freeing the table. */ + table->parent= NULL; + /* Free table. */ + VOID(hash_delete(&open_cache, (uchar *) table)); + } + else + { + *prev= table; + prev= &table->next; + } } + *prev= 0; } DBUG_PRINT("tcache", ("open tables to lock: %u", (uint) (tables_ptr - tables))); From 27728ab9857ef2f23ad15f1a4b9b493947f2d1e4 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 18 Aug 2011 16:35:46 +0200 Subject: [PATCH 042/143] BUG#12818561 - RELEASE-LIKE PACKAGE CONTAINS AN EXTRA 'PLUGIN' FOLDER Look for suite/thread_pool/plugin.defs --- mysql-test/mysql-test-run.pl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ec0ca74b1d1..9dc4f2e515e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -450,8 +450,9 @@ sub main { # read_plugin_defs("include/plugin.defs"); - # Also read from any plugin local plugin.defs - for (glob "$basedir/plugin/*/tests/mtr/plugin.defs") { + # Also read from any plugin local or suite specific plugin.defs + for (glob "$basedir/plugin/*/tests/mtr/plugin.defs". + " suite/*/plugin.defs") { read_plugin_defs($_); } From e8f2e3c2176a1625220b3189e73bba91dae7684c Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 19 Aug 2011 18:48:14 +0200 Subject: [PATCH 043/143] Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" On Fedora, certain accesses to "/var/lib/mysql/HOSTNAME.err" were blocked by SELinux policy, this made the server start fail with the message Manager of pid-file quit without updating file Calling "/sbin/restorecon -R /var/lib/mysql" fixes this. --- support-files/mysql.spec.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 006dea45e64..28f2b0f773a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -382,7 +382,7 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --enable-local-infile \ --with-fast-mutexes \ --with-mysqld-user=%{mysqld_user} \ - --with-unix-socket-path=/var/lib/mysql/mysql.sock \ + --with-unix-socket-path=%{mysqldatadir}/mysql.sock \ --with-pic \ --prefix=/ \ %if %{CLUSTER_BUILD} @@ -858,6 +858,13 @@ chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir # ---------------------------------------------------------------------- chmod -R og-rw $mysql_datadir/mysql +# ---------------------------------------------------------------------- +# Deal with SELinux, if it is installed / used +# ---------------------------------------------------------------------- +if [ -x /sbin/restorecon ] ; then + /sbin/restorecon -R %{mysqldatadir} +fi + # Was the server running before the upgrade? If so, restart the new one. if [ "$SERVER_TO_START" = "true" ] ; then # Restart in the same way that mysqld will be started normally. @@ -1165,6 +1172,15 @@ fi # merging BK trees) ############################################################################## %changelog +* Fri Aug 19 2011 Joerg Bruehe + +- Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" + On Fedora, certain accesses to "/var/lib/mysql/HOSTNAME.err" were blocked + by SELinux policy, this made the server start fail with the message + Manager of pid-file quit without updating file + Calling "/sbin/restorecon -R /var/lib/mysql" fixes this. +- Replace occurrences of that path name by the spec file variable %{mysqldatadir}. + * Thu Jul 07 2011 Joerg Bruehe - Fix bug#45415: "rpm upgrade recreates test database" From 4cb3072356553a003848c8e72f659361ba58c59b Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 22 Aug 2011 13:58:49 +0200 Subject: [PATCH 044/143] Bug #12793170 MYSQLTEST: PROVIDE ACCESS TO ERROR NAMES THROUGH NUMERIC CODES AND VICE VERSA Added a second internal variable $mysql_errname This is set the same way as $mysql_errno Can be used like "if ($mysql_errname == ER_NO_SUCH_TABLE)...." --- client/mysqltest.cc | 34 +++++++++++++++------- mysql-test/r/execution_constants.result | 2 +- mysql-test/r/mysqltest.result | 23 +++++++++++++-- mysql-test/t/execution_constants.test | 10 +++---- mysql-test/t/mysqltest.test | 38 +++++++++++++++++++------ 5 files changed, 79 insertions(+), 28 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index cc5dd1f377c..93d475cbf7e 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -494,6 +494,7 @@ void str_to_file(const char *fname, char *str, int size); void str_to_file2(const char *fname, char *str, int size, my_bool append); void fix_win_paths(const char *val, int len); +const char *get_errname_from_code (uint error_code); #ifdef __WIN__ void free_tmp_sh_file(); @@ -2263,6 +2264,7 @@ void var_set_int(const char* name, int value) void var_set_errno(int sql_errno) { var_set_int("$mysql_errno", sql_errno); + var_set_string("$mysql_errname", get_errname_from_code(sql_errno)); } @@ -4670,8 +4672,7 @@ void do_shutdown_server(struct st_command *command) } -#if MYSQL_VERSION_ID >= 50000 -/* List of error names to error codes, available from 5.0 */ +/* List of error names to error codes */ typedef struct { const char *name; @@ -4681,6 +4682,7 @@ typedef struct static st_error global_error_names[] = { + { "", -1, "" }, #include { 0, 0, 0 } }; @@ -4711,16 +4713,28 @@ uint get_errcode_from_name(char *error_name, char *error_end) die("Unknown SQL error name '%s'", error_name); DBUG_RETURN(0); } -#else -uint get_errcode_from_name(char *error_name __attribute__((unused)), - char *error_end __attribute__((unused))) + +const char *get_errname_from_code (uint error_code) { - abort_not_in_this_version(); - return 0; /* Never reached */ + st_error *e= global_error_names; + + DBUG_ENTER("get_errname_from_code"); + DBUG_PRINT("enter", ("error_code: %d", error_code)); + + if (! error_code) + { + DBUG_RETURN(""); + } + for (; e->name; e++) + { + if (e->code == error_code) + { + DBUG_RETURN(e->name); + } + } + die("Unknown SQL error code '%d'", error_code); } -#endif - - + void do_get_errcodes(struct st_command *command) { diff --git a/mysql-test/r/execution_constants.result b/mysql-test/r/execution_constants.result index 293c88dc506..86eed447b83 100644 --- a/mysql-test/r/execution_constants.result +++ b/mysql-test/r/execution_constants.result @@ -7,6 +7,6 @@ PRIMARY KEY (`ID_MEMBER`,`ID_BOARD`), KEY `logTime` (`logTime`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 COLLATE=cp1251_bulgarian_ci; INSERT INTO `t_bug21476` VALUES (2,2,1154870939,0),(1,2,1154870957,0),(2,183,1154941362,0),(2,84,1154904301,0),(1,84,1154905867,0),(2,13,1154947484,10271),(3,84,1154880549,0),(1,6,1154892183,0),(2,25,1154947581,10271),(3,25,1154904760,0),(1,25,1154947373,10271),(1,179,1154899992,0),(2,179,1154899410,0),(5,25,1154901666,0),(2,329,1154902026,0),(3,329,1154902040,0),(1,329,1154902058,0),(1,13,1154930841,0),(3,85,1154904987,0),(1,183,1154929665,0),(3,13,1154931268,0),(1,85,1154936888,0),(1,169,1154937959,0),(2,169,1154941717,0),(3,183,1154939810,0),(3,169,1154941734,0); -Assertion: mysql_errno 1436 == 1436 +Assertion: mysql_errname ER_STACK_OVERRUN_NEED_MORE == ER_STACK_OVERRUN_NEED_MORE DROP TABLE `t_bug21476`; End of 5.0 tests. diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 9c8f49c333b..9d000e6f782 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -1,6 +1,5 @@ -select 0 as "before_use_test" ; -before_use_test -0 +-1 before test + before test select otto from (select 1 as otto) as t1; otto 1 @@ -21,27 +20,32 @@ mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' fai select otto from (select 1 as otto) as t1; otto 1 + select 0 as "after_successful_stmt_errno" ; after_successful_stmt_errno 0 garbage ; 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 'garbage' at line 1 +ER_PARSE_ERROR select 1064 as "after_wrong_syntax_errno" ; after_wrong_syntax_errno 1064 garbage ; 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 'garbage' at line 1 +ER_PARSE_ERROR select 1064 as "after_let_var_equal_value" ; after_let_var_equal_value 1064 garbage ; 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 'garbage' at line 1 set @my_var= 'abc' ; + select 0 as "after_set_var_equal_value" ; after_set_var_equal_value 0 garbage ; 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 'garbage' at line 1 +ER_PARSE_ERROR select 1064 as "after_disable_warnings_command" ; after_disable_warnings_command 1064 @@ -49,6 +53,7 @@ drop table if exists t1 ; garbage ; 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 'garbage' at line 1 drop table if exists t1 ; + select 0 as "after_disable_warnings" ; after_disable_warnings 0 @@ -56,6 +61,7 @@ garbage ; 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 'garbage' at line 1 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist +ER_NO_SUCH_TABLE select 1146 as "after_minus_masked" ; after_minus_masked 1146 @@ -63,6 +69,7 @@ garbage ; 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 'garbage' at line 1 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist +ER_NO_SUCH_TABLE select 1146 as "after_!_masked" ; after_!_masked 1146 @@ -75,6 +82,7 @@ garbage ; 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 'garbage' at line 1 prepare stmt from "select 3 from t1" ; ERROR 42S02: Table 'test.t1' doesn't exist +ER_NO_SUCH_TABLE select 1146 as "after_failing_prepare" ; after_failing_prepare 1146 @@ -82,6 +90,7 @@ create table t1 ( f1 char(10)); garbage ; 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 'garbage' at line 1 prepare stmt from "select 3 from t1" ; + select 0 as "after_successful_prepare" ; after_successful_prepare 0 @@ -89,6 +98,7 @@ garbage ; 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 'garbage' at line 1 execute stmt; 3 + select 0 as "after_successful_execute" ; after_successful_execute 0 @@ -97,6 +107,7 @@ garbage ; 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 'garbage' at line 1 execute stmt; ERROR 42S02: Table 'test.t1' doesn't exist +ER_NO_SUCH_TABLE select 1146 as "after_failing_execute" ; after_failing_execute 1146 @@ -104,12 +115,14 @@ garbage ; 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 'garbage' at line 1 execute __stmt_; ERROR HY000: Unknown prepared statement handler (__stmt_) given to EXECUTE +ER_UNKNOWN_STMT_HANDLER select 1243 as "after_failing_execute" ; after_failing_execute 1243 garbage ; 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 'garbage' at line 1 deallocate prepare stmt; + select 0 as "after_successful_deallocate" ; after_successful_deallocate 0 @@ -117,11 +130,13 @@ garbage ; 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 'garbage' at line 1 deallocate prepare __stmt_; ERROR HY000: Unknown prepared statement handler (__stmt_) given to DEALLOCATE PREPARE +ER_UNKNOWN_STMT_HANDLER select 1243 as "after_failing_deallocate" ; after_failing_deallocate 1243 garbage ; 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 'garbage' at line 1 +ER_PARSE_ERROR select 1064 as "after_--disable_abort_on_error" ; after_--disable_abort_on_error 1064 @@ -131,12 +146,14 @@ select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist +ER_NO_SUCH_TABLE select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1000... garbage ; 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 'garbage' at line 1 +ER_PARSE_ERROR select 1064 as "after_--enable_abort_on_error" ; after_--enable_abort_on_error 1064 diff --git a/mysql-test/t/execution_constants.test b/mysql-test/t/execution_constants.test index 92b1deb9921..285197cd1f4 100644 --- a/mysql-test/t/execution_constants.test +++ b/mysql-test/t/execution_constants.test @@ -38,7 +38,7 @@ while ($i) { # If we SEGV because the min stack size is exceeded, this would return error # 2013 . - error 0,1436 // + error 0,ER_STACK_OVERRUN_NEED_MORE // eval $query_head 0 $query_tail// if ($mysql_errno) @@ -48,10 +48,10 @@ while ($i) # limit, we still have enough space reserved to report an error. let $i = 1// - # Check that mysql_errno is 1436 - if ($mysql_errno != 1436) + # Check that mysql_errname is ER_STACK_OVERRUN_NEED_MORE + if ($mysql_errname != ER_STACK_OVERRUN_NEED_MORE) { - die Wrong error triggered, expected 1436 but got $mysql_errno// + die Wrong error triggered, expected ER_STACK_OVERRUN_NEED_MORE but got $mysql_errname// } } @@ -76,7 +76,7 @@ while ($i) enable_result_log// enable_query_log// -echo Assertion: mysql_errno 1436 == $mysql_errno// +echo Assertion: mysql_errname ER_STACK_OVERRUN_NEED_MORE == $mysql_errname// delimiter ;// DROP TABLE `t_bug21476`; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 9ff92496653..9fa41b9eb51 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1,3 +1,14 @@ +# ---------------------------------------------------------------------------- +# $mysql_errno contains the return code of the last command +# sent to the server. +# ---------------------------------------------------------------------------- +# get $mysql_errno before the first statement +# $mysql_errno should be -1 +# get $mysql_errname as well + +echo $mysql_errno before test; +echo $mysql_errname before test; + -- source include/have_log_bin.inc # This test should work in embedded server after mysqltest is fixed @@ -33,15 +44,6 @@ # # ============================================================================ -# ---------------------------------------------------------------------------- -# $mysql_errno contains the return code of the last command -# sent to the server. -# ---------------------------------------------------------------------------- -# get $mysql_errno before the first statement -# $mysql_errno should be -1 -eval select $mysql_errno as "before_use_test" ; - - # ---------------------------------------------------------------------------- # Positive case(statement) # ---------------------------------------------------------------------------- @@ -134,6 +136,7 @@ select friedrich from (select 1 as otto) as t1; # check mysql_errno = 0 after successful statement # ---------------------------------------------------------------------------- select otto from (select 1 as otto) as t1; +echo $mysql_errname; eval select $mysql_errno as "after_successful_stmt_errno" ; #---------------------------------------------------------------------------- @@ -142,6 +145,7 @@ eval select $mysql_errno as "after_successful_stmt_errno" ; --error ER_PARSE_ERROR garbage ; +echo $mysql_errname; eval select $mysql_errno as "after_wrong_syntax_errno" ; # ---------------------------------------------------------------------------- @@ -151,6 +155,7 @@ eval select $mysql_errno as "after_wrong_syntax_errno" ; garbage ; let $my_var= 'abc' ; +echo $mysql_errname; eval select $mysql_errno as "after_let_var_equal_value" ; # ---------------------------------------------------------------------------- @@ -160,6 +165,7 @@ eval select $mysql_errno as "after_let_var_equal_value" ; garbage ; set @my_var= 'abc' ; +echo $mysql_errname; eval select $mysql_errno as "after_set_var_equal_value" ; # ---------------------------------------------------------------------------- @@ -170,6 +176,7 @@ eval select $mysql_errno as "after_set_var_equal_value" ; garbage ; --disable_warnings +echo $mysql_errname; eval select $mysql_errno as "after_disable_warnings_command" ; # ---------------------------------------------------------------------------- @@ -182,6 +189,7 @@ drop table if exists t1 ; garbage ; drop table if exists t1 ; +echo $mysql_errname; eval select $mysql_errno as "after_disable_warnings" ; --enable_warnings @@ -194,6 +202,7 @@ garbage ; --error ER_NO_SUCH_TABLE select 3 from t1 ; +echo $mysql_errname; eval select $mysql_errno as "after_minus_masked" ; --error ER_PARSE_ERROR @@ -201,6 +210,7 @@ garbage ; --error ER_NO_SUCH_TABLE select 3 from t1 ; +echo $mysql_errname; eval select $mysql_errno as "after_!_masked" ; # ---------------------------------------------------------------------------- @@ -222,6 +232,7 @@ garbage ; --error ER_NO_SUCH_TABLE prepare stmt from "select 3 from t1" ; +echo $mysql_errname; eval select $mysql_errno as "after_failing_prepare" ; create table t1 ( f1 char(10)); @@ -230,6 +241,7 @@ create table t1 ( f1 char(10)); garbage ; prepare stmt from "select 3 from t1" ; +echo $mysql_errname; eval select $mysql_errno as "after_successful_prepare" ; # successful execute @@ -237,6 +249,7 @@ eval select $mysql_errno as "after_successful_prepare" ; garbage ; execute stmt; +echo $mysql_errname; eval select $mysql_errno as "after_successful_execute" ; # failing execute (table has been dropped) @@ -247,6 +260,7 @@ garbage ; --error ER_NO_SUCH_TABLE execute stmt; +echo $mysql_errname; eval select $mysql_errno as "after_failing_execute" ; # failing execute (unknown statement) @@ -256,6 +270,7 @@ garbage ; --error ER_UNKNOWN_STMT_HANDLER execute __stmt_; +echo $mysql_errname; eval select $mysql_errno as "after_failing_execute" ; # successful deallocate @@ -263,6 +278,7 @@ eval select $mysql_errno as "after_failing_execute" ; garbage ; deallocate prepare stmt; +echo $mysql_errname; eval select $mysql_errno as "after_successful_deallocate" ; # failing deallocate ( statement handle does not exist ) @@ -272,6 +288,7 @@ garbage ; --error ER_UNKNOWN_STMT_HANDLER deallocate prepare __stmt_; +echo $mysql_errname; eval select $mysql_errno as "after_failing_deallocate" ; @@ -299,6 +316,7 @@ eval select $mysql_errno as "after_failing_deallocate" ; garbage ; --disable_abort_on_error +echo $mysql_errname; eval select $mysql_errno as "after_--disable_abort_on_error" ; # ---------------------------------------------------------------------------- @@ -316,6 +334,7 @@ select 3 from t1 ; --error ER_NO_SUCH_TABLE select 3 from t1 ; +echo $mysql_errname; eval select $mysql_errno as "after_!errno_masked_error" ; # expected error <> response # --error 1000 @@ -341,6 +360,7 @@ EOF garbage ; --enable_abort_on_error +echo $mysql_errname; eval select $mysql_errno as "after_--enable_abort_on_error" ; # ---------------------------------------------------------------------------- From 6e60a071576e422aa6f9275d76209596ce63e4bf Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 22 Aug 2011 14:42:12 +0200 Subject: [PATCH 045/143] Bug #12793170 MYSQLTEST: PROVIDE ACCESS TO ERROR NAMES THROUGH NUMERIC CODES AND VICE VERSA Followup: Some statement may give errors not in the list, map these to "" rather than failing. --- client/mysqltest.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 93d475cbf7e..903f6a024f7 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -4732,9 +4732,9 @@ const char *get_errname_from_code (uint error_code) DBUG_RETURN(e->name); } } - die("Unknown SQL error code '%d'", error_code); -} - + /* Apparently, errors without known names may occur */ + DBUG_RETURN(""); +} void do_get_errcodes(struct st_command *command) { From 49ee12d03b763a460cfcc371566465019a4dc067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 22 Aug 2011 17:03:07 +0300 Subject: [PATCH 046/143] Bug #11766591 59733: POSSIBLE DEADLOCK WHEN BUFFERED CHANGES ARE TO BE DISCARDED The fix in revision id marko.makela@oracle.com-20110815091143-h3zbvm0pv8ni3qql introduced a false UNIV_SYNC_DEBUG alarm. Relax the assertion. --- storage/innodb_plugin/sync/sync0sync.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 1b97e1f11f3..64aadffdfad 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1248,7 +1248,13 @@ sync_thread_add_level( TRUE)); break; case SYNC_IBUF_TREE_NODE_NEW: - ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + /* ibuf_add_free_page() allocates new pages for the + change buffer while only holding the tablespace + x-latch. These pre-allocated new pages may only be + taken in use while holding ibuf_mutex, in + btr_page_alloc_for_ibuf(). */ + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) + || sync_thread_levels_contain(array, SYNC_FSP)); break; case SYNC_IBUF_INDEX_TREE: if (sync_thread_levels_contain(array, SYNC_FSP)) { From c640e6a048eac58a25e0d82467943386015667c6 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 24 Aug 2011 14:38:57 +0200 Subject: [PATCH 047/143] MTR: small fix to read_plugin_defs for RPM builds: Also look into directories lib64 in addition to lib --- 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 168115cbc6b..451b877f9a8 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2132,8 +2132,10 @@ sub find_plugin($$) my $lib_plugin= mtr_file_exists(vs_config_dirs($location,$plugin_filename), "$basedir/lib/plugin/".$plugin_filename, + "$basedir/lib64/plugin/".$plugin_filename, "$basedir/$location/.libs/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename, + "$basedir/lib64/mysql/plugin/".$plugin_filename, ); return $lib_plugin; } From 34efcfa4db3e9cb0a03f609c62b662fafbdd1170 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 24 Aug 2011 15:16:24 +0200 Subject: [PATCH 048/143] MTR: small fix to read_plugin_defs for RPM builds: Also look into directories lib64 in addition to lib --- 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 9dc4f2e515e..1f02a5fb08e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2133,8 +2133,10 @@ sub find_plugin($$) my $lib_plugin= mtr_file_exists(vs_config_dirs($location,$plugin_filename), "$basedir/lib/plugin/".$plugin_filename, + "$basedir/lib64/plugin/".$plugin_filename, "$basedir/$location/.libs/".$plugin_filename, "$basedir/lib/mysql/plugin/".$plugin_filename, + "$basedir/lib64/mysql/plugin/".$plugin_filename, ); return $lib_plugin; } From 9906e9cf7254073fef9ad8d65780445b8754dd24 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 24 Aug 2011 15:22:33 +0200 Subject: [PATCH 049/143] Backporting fix from trunk (revid 3381), original comment: Blind attempt to fix BUG 12881278 - MAIN.MYISAM TEST FAILS ON LINUX The printed text is truncated on char 63: "MySQL thread id 1236, OS thread handle 0x7ff187b96700, query id" still I do not understand how this truncation could have caused the main.myisam failure but anyway - the buffer needs to be increased. --- sql/sql_class.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0b1de2c47fa..9b5772d3d07 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -641,7 +641,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, { String str(buffer, length, &my_charset_latin1); const Security_context *sctx= &thd->main_security_ctx; - char header[64]; + char header[256]; int len; /* The pointers thd->query and thd->proc_info might change since they are From 0c7db7839b052269e034d91a7597a74b3d1f90ba Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 25 Aug 2011 10:38:07 +0200 Subject: [PATCH 050/143] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Suppress the known warnings generated by filesort(). The real fix belongs to worklog 1509: Pack values of non-sorted fields in the sort buffer (which is basically the same issue, but in an optimization context: We are writing the entire sort buffer to disk, including un-used space for varchar columns.) mysql-test/valgrind.supp: Add new Memcheck suppressions for filesort. sql/filesort.cc: Remove the ifdef HAVE_purify/bzero code, use valgrind suppressions instead. --- mysql-test/valgrind.supp | 34 ++++++++++++++++++++++++++++++++++ sql/filesort.cc | 11 ----------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 8720cd511b9..3751a339a1a 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -791,3 +791,37 @@ fun:fil_delete_tablespace fun:row_drop_table_for_mysql } + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_my_b_write + fun:_ZL10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ + fun:_ZL13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / three + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} diff --git a/sql/filesort.cc b/sql/filesort.cc index 99e5156427a..0ff354b334c 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -959,21 +959,10 @@ static void make_sortkey(register SORTPARAM *param, if (addonf->null_bit && field->is_null()) { nulls[addonf->null_offset]|= addonf->null_bit; -#ifdef HAVE_purify - bzero(to, addonf->length); -#endif } else { -#ifdef HAVE_purify - uchar *end= field->pack(to, field->ptr); - uint length= (uint) ((to + addonf->length) - end); - DBUG_ASSERT((int) length >= 0); - if (length) - bzero(end, length); -#else (void) field->pack(to, field->ptr); -#endif } to+= addonf->length; } From e46b3453bfd379f7eef4fcc01853f085007c012b Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Fri, 26 Aug 2011 15:27:29 +0530 Subject: [PATCH 051/143] BUG#11878104: FIXES OF BUG 11752963 - 44312 TO BACKPORT TO MYSQL-5.1 Background: Backporting fix for BUG 11752963 to Mysql5.1 branch. Problem: Fix of bug 11752963 was only available for trunk and 5.5 branch. Partial fix has been pushed to 5.1 branch as well. Fix: backporting the fixes of bug 11752963 to 5.1 branch. 1. Made all major changes to make 5.1 branch in line with 5.5 and the trunk. 2. skipped the partial patch that was already applied to the 5.1 branch. sql/rpl_rli.h: Made inited Volatile (find inline comments) sql/slave.cc: backported all changes from the fix of BUG#11752963. --- sql/rpl_rli.h | 8 +++++++- sql/slave.cc | 11 ++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 811ad8eb864..ae8639c69ac 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -221,7 +221,13 @@ public: #endif /* if not set, the value of other members of the structure are undefined */ - bool inited; + /* + inited changes its value within LOCK_active_mi-guarded critical + sections at times of start_slave_threads() (0->1) and end_slave() (1->0). + Readers may not acquire the mutex while they realize potential concurrency + issue. + */ + volatile bool inited; volatile bool abort_slave; volatile uint slave_running; diff --git a/sql/slave.cc b/sql/slave.cc index 6c375238ce4..02d8cc2c199 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -598,11 +598,15 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, DBUG_PRINT("sleep",("Waiting for slave thread to start")); const char* old_msg = thd->enter_cond(start_cond,cond_lock, "Waiting for slave thread to start"); - pthread_cond_wait(start_cond,cond_lock); + pthread_cond_wait(start_cond, cond_lock); thd->exit_cond(old_msg); pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released if (thd->killed) + { + if (start_lock) + pthread_mutex_unlock(start_lock); DBUG_RETURN(thd->killed_errno()); + } } } if (start_lock) @@ -2531,6 +2535,7 @@ pthread_handler_t handle_slave_io(void *arg) thd= new THD; // note that contructor of THD uses DBUG_ ! THD_CHECK_SENTRY(thd); + DBUG_ASSERT(mi->io_thd == 0); mi->io_thd = thd; pthread_detach_this_thread(); @@ -4489,9 +4494,6 @@ int rotate_relay_log(Master_info* mi) Relay_log_info* rli= &mi->rli; int error= 0; - /* We don't lock rli->run_lock. This would lead to deadlocks. */ - pthread_mutex_lock(&mi->run_lock); - /* We need to test inited because otherwise, new_file() will attempt to lock LOCK_log, which may not be inited (if we're not a slave). @@ -4521,7 +4523,6 @@ int rotate_relay_log(Master_info* mi) */ rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: - pthread_mutex_unlock(&mi->run_lock); DBUG_RETURN(error); } From d9ceec6631d9bea76ec3b76636e002356bfcf366 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 29 Aug 2011 10:07:18 +0200 Subject: [PATCH 052/143] Bug#12856915 adapt valgrind suppressions to 5.5 --- mysql-test/valgrind.supp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index a0345684cb4..f6bf8a690e4 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -883,23 +883,24 @@ write(buf) obj:*/libpthread*.so fun:my_write + fun:inline_mysql_file_write fun:my_b_flush_io_cache fun:_my_b_write fun:_ZL10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ fun:_ZL13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ - fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy + fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy } -{ - Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two - Memcheck:Param - write(buf) - obj:*/libpthread*.so - fun:my_write - fun:my_b_flush_io_cache - fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache - fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy -} +## { +## Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two +## Memcheck:Param +## write(buf) +## obj:*/libpthread*.so +## fun:my_write +## fun:my_b_flush_io_cache +## fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache +## fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +## } { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / three @@ -907,6 +908,7 @@ write(buf) obj:*/libpthread*.so fun:my_write + fun:inline_mysql_file_write fun:my_b_flush_io_cache - fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy + fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy } From 41f229cd9ed5a1549fb6438bdc1614e48d003625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Aug 2011 11:16:42 +0300 Subject: [PATCH 053/143] Bug#12704861 Corruption after a crash during BLOB update The fix of Bug#12612184 broke crash recovery. When a record that contains off-page columns (BLOBs) is updated, we must first write redo log about the BLOB page writes, and only after that write the redo log about the B-tree changes. The buggy fix would log the B-tree changes first, meaning that after recovery, we could end up having a record that contains a null BLOB pointer. Because we will be redo logging the writes off the off-page columns before the B-tree changes, we must make sure that the pages chosen for the off-page columns are free both before and after the B-tree changes. In this way, the worst thing that can happen in crash recovery is that the BLOBs are written to free pages, but the B-tree changes are not applied. The BLOB pages would correctly remain free in this case. To achieve this, we must allocate the BLOB pages in the mini-transaction of the B-tree operation. A further quirk is that BLOB pages are allocated from the same file segment as leaf pages. Because of this, we must temporarily "hide" any leaf pages that were freed during the B-tree operation by "fake allocating" them prior to writing the BLOBs, and freeing them again before the mtr_commit() of the B-tree operation, in btr_mark_freed_leaves(). btr_cur_mtr_commit_and_start(): Remove this faulty function that was introduced in the Bug#12612184 fix. The problem that this function was trying to address was that when we did mtr_commit() the BLOB writes before the mtr_commit() of the update, the new BLOB pages could have overwritten clustered index B-tree leaf pages that were freed during the update. If recovery applied the redo log of the BLOB writes but did not see the log of the record update, the index tree would be corrupted. The correct solution is to make the freed clustered index pages unavailable to the BLOB allocation. This function is also a likely culprit of InnoDB hangs that were observed when testing the Bug#12612184 fix. btr_mark_freed_leaves(): Mark all freed clustered index leaf pages of a mini-transaction allocated (nonfree=TRUE) before storing the BLOBs, or freed (nonfree=FALSE) before committing the mini-transaction. btr_freed_leaves_validate(): A debug function for checking that all clustered index leaf pages that have been marked free in the mini-transaction are consistent (have not been zeroed out). btr_page_alloc_low(): Refactored from btr_page_alloc(). Return the number of the allocated page, or FIL_NULL if out of space. Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized, or if this is a "fake allocation" (init_mtr=NULL) by btr_mark_freed_leaves(nonfree=TRUE). btr_page_alloc(): Add the parameter init_mtr, allowing the page to be initialized and X-latched in a different mini-transaction than the one that is used for the allocation. Invoke btr_page_alloc_low(). If a clustered index leaf page was previously freed in mtr, remove it from the memo of previously freed pages. btr_page_free(): Assert that the page is a B-tree page and it has been X-latched by the mini-transaction. If the freed page was a leaf page of a clustered index, link it by a MTR_MEMO_FREE_CLUST_LEAF marker to the mini-transaction. btr_store_big_rec_extern_fields_func(): Add the parameter alloc_mtr, which is NULL (old behaviour in inserts) and the same as local_mtr in updates. If alloc_mtr!=NULL, the BLOB pages will be allocated from it instead of the mini-transaction that is used for writing the BLOBs. fsp_alloc_from_free_frag(): Refactored from fsp_alloc_free_page(). Allocate the specified page from a partially free extent. fseg_alloc_free_page_low(), fseg_alloc_free_page_general(): Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized, or NULL if this is a "fake allocation" that prevents the reuse of a previously freed B-tree page for BLOB storage. If init_mtr==NULL, try harder to reallocate the specified page and assert that it succeeded. fsp_alloc_free_page(): Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized. Do not allow init_mtr == NULL, because this function is never to be used for "fake allocations". mtr_t: Add the operation MTR_MEMO_FREE_CLUST_LEAF and the flag mtr->freed_clust_leaf for quickly determining if any MTR_MEMO_FREE_CLUST_LEAF operations have been posted. row_ins_index_entry_low(): When columns are being made off-page in insert-by-update, invoke btr_mark_freed_leaves(nonfree=TRUE) and pass the mini-transaction as the alloc_mtr to btr_store_big_rec_extern_fields(). Finally, invoke btr_mark_freed_leaves(nonfree=FALSE) to avoid leaking pages. row_build(): Correct a comment, and add a debug assertion that a record that contains NULL BLOB pointers must be a fresh insert. row_upd_clust_rec(): When columns are being moved off-page, invoke btr_mark_freed_leaves(nonfree=TRUE) and pass the mini-transaction as the alloc_mtr to btr_store_big_rec_extern_fields(). Finally, invoke btr_mark_freed_leaves(nonfree=FALSE) to avoid leaking pages. buf_reset_check_index_page_at_flush(): Remove. The function fsp_init_file_page_low() already sets bpage->check_index_page_at_flush=FALSE. There is a known issue in tablespace extension. If the request to allocate a BLOB page leads to the tablespace being extended, crash recovery could see BLOB writes to pages that are off the tablespace file bounds. This should trigger an assertion failure in fil_io() at crash recovery. The safe thing would be to write redo log about the tablespace extension to the mini-transaction of the BLOB write, not to the mini-transaction of the record update. However, there is no redo log record for file extension in the current redo log format. rb:693 approved by Sunny Bains --- .../suite/innodb_plugin/r/innodb-index.result | 9 + .../suite/innodb_plugin/t/innodb-index.test | 13 + storage/innobase/btr/btr0btr.c | 222 +++++++++++++++-- storage/innobase/btr/btr0cur.c | 92 ++++--- storage/innobase/buf/buf0buf.c | 23 -- storage/innobase/fsp/fsp0fsp.c | 168 +++++++++---- storage/innobase/include/btr0btr.h | 31 ++- storage/innobase/include/btr0cur.h | 14 +- storage/innobase/include/buf0buf.h | 9 - storage/innobase/include/fsp0fsp.h | 8 +- storage/innobase/include/mtr0mtr.h | 7 +- storage/innobase/include/mtr0mtr.ic | 4 +- storage/innobase/mtr/mtr0mtr.c | 10 +- storage/innobase/row/row0ins.c | 32 ++- storage/innobase/row/row0row.c | 32 +-- storage/innobase/row/row0upd.c | 21 +- storage/innobase/trx/trx0undo.c | 2 +- storage/innodb_plugin/ChangeLog | 14 ++ storage/innodb_plugin/btr/btr0btr.c | 220 ++++++++++++++-- storage/innodb_plugin/btr/btr0cur.c | 114 +++++---- storage/innodb_plugin/buf/buf0buf.c | 23 -- storage/innodb_plugin/fsp/fsp0fsp.c | 234 +++++++++++------- storage/innodb_plugin/include/btr0btr.h | 34 ++- storage/innodb_plugin/include/btr0cur.h | 38 ++- storage/innodb_plugin/include/buf0buf.h | 9 - storage/innodb_plugin/include/fsp0fsp.h | 30 ++- storage/innodb_plugin/include/mtr0mtr.h | 13 +- storage/innodb_plugin/include/mtr0mtr.ic | 6 +- storage/innodb_plugin/include/trx0undo.h | 46 +++- storage/innodb_plugin/mtr/mtr0mtr.c | 7 +- storage/innodb_plugin/row/row0ins.c | 31 ++- storage/innodb_plugin/row/row0row.c | 25 +- storage/innodb_plugin/row/row0upd.c | 21 +- storage/innodb_plugin/trx/trx0rec.c | 68 +++-- storage/innodb_plugin/trx/trx0undo.c | 70 +++--- 35 files changed, 1148 insertions(+), 552 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index b24f282dfc4..5be1460d2b7 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -1024,6 +1024,15 @@ 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)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731)); +COMMIT; +UPDATE bug12547647 SET c = REPEAT('b',16928); +ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +DROP TABLE bug12547647; set global innodb_file_per_table=0; set global innodb_file_format=Antelope; set global innodb_file_format_check=Antelope; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index 52f94990b15..b4e2aae09e9 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -480,6 +480,19 @@ DELETE FROM t1; -- 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, +PRIMARY KEY (b(10), a), INDEX (c(10)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731)); +COMMIT; +# The following used to cause infinite undo log allocation. +--error ER_TOO_BIG_ROWSIZE +UPDATE bug12547647 SET c = REPEAT('b',16928); +DROP TABLE bug12547647; + eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; eval set global innodb_file_format_check=$format; diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 790582815a3..ad99913cf3b 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -300,29 +300,30 @@ btr_page_alloc_for_ibuf( /****************************************************************** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! */ - -page_t* -btr_page_alloc( -/*===========*/ - /* out: new allocated page, x-latched; - NULL if out of space */ +static +ulint +btr_page_alloc_low( +/*===============*/ + /* out: allocated page number, + FIL_NULL if out of space */ dict_index_t* index, /* in: index */ ulint hint_page_no, /* in: hint of a good page */ byte file_direction, /* in: direction where a possible page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /* in/out: mini-transaction + in which the page should be + initialized (may be the same + as mtr), or NULL if it should + not be initialized (the page + at hint was previously freed + in mtr) */ { fseg_header_t* seg_header; page_t* root; - page_t* new_page; - ulint new_page_no; - - if (index->type & DICT_IBUF) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } root = btr_root_get(index, mtr); @@ -336,19 +337,61 @@ btr_page_alloc( reservation for free extents, and thus we know that a page can be allocated: */ - new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, mtr); + return(fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, + mtr, init_mtr)); +} + +/**************************************************************//** +Allocates a new file page to be used in an index tree. NOTE: we assume +that the caller has made the reservation for free extents! */ + +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated block, x-latched; + NULL if out of space */ + dict_index_t* index, /* in: index */ + ulint hint_page_no, /* in: hint of a good page */ + byte file_direction, /* in: direction where a possible + page split is made */ + ulint level, /* in: level where the page is placed + in the tree */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /* in/out: mini-transaction + for x-latching and initializing + the page */ +{ + page_t* new_page; + ulint new_page_no; + + if (index->type & DICT_IBUF) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } + + new_page_no = btr_page_alloc_low( + index, hint_page_no, file_direction, level, mtr, init_mtr); + if (new_page_no == FIL_NULL) { return(NULL); } new_page = buf_page_get(dict_index_get_space(index), new_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, init_mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ + if (mtr->freed_clust_leaf) { + mtr_memo_release(mtr, new_page, MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(!mtr_memo_contains(mtr, buf_block_align(new_page), + MTR_MEMO_FREE_CLUST_LEAF)); + } + + ut_ad(btr_freed_leaves_validate(mtr)); return(new_page); } @@ -464,6 +507,16 @@ btr_page_free_low( page_no = buf_frame_get_page_no(page); fseg_free_page(seg_header, space, page_no, mtr); + + /* The page was marked free in the allocation bitmap, but it + should remain buffer-fixed until mtr_commit(mtr) or until it + is explicitly freed from the mini-transaction. */ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* TODO: Discard any operations on the page from the redo log + and remove the block from the flush list and the buffer pool. + This would free up buffer pool earlier and reduce writes to + both the tablespace and the redo log. */ } /****************************************************************** @@ -479,13 +532,144 @@ btr_page_free( { ulint level; + ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); level = btr_page_get_level(page, mtr); btr_page_free_low(index, page, level, mtr); + + /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + + if (level == 0 && (index->type & DICT_CLUSTERED)) { + /* We may have to call btr_mark_freed_leaves() to + temporarily mark the block nonfree for invoking + btr_store_big_rec_extern_fields() after an + update. Remember that the block was freed. */ + mtr->freed_clust_leaf = TRUE; + mtr_memo_push(mtr, buf_block_align(page), + MTR_MEMO_FREE_CLUST_LEAF); + } + + ut_ad(btr_freed_leaves_validate(mtr)); } +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ + +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /* in/out: clustered index */ + mtr_t* mtr, /* in/out: mini-transaction */ + ibool nonfree)/* in: TRUE=mark nonfree, FALSE=mark freed */ +{ + /* This is loosely based on mtr_memo_release(). */ + + ulint offset; + + ut_ad(index->type & DICT_CLUSTERED); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + if (!mtr->freed_clust_leaf) { + return; + } + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(buf_block_get_space(block) + == dict_index_get_space(index)); + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); + + if (nonfree) { + /* Allocate the same page again. */ + ulint page_no; + page_no = btr_page_alloc_low( + index, buf_block_get_page_no(block), + FSP_NO_DIR, 0, mtr, NULL); + ut_a(page_no == buf_block_get_page_no(block)); + } else { + /* Assert that the page is allocated and free it. */ + btr_page_free_low(index, buf_block_get_frame(block), + 0, mtr); + } + } + + ut_ad(btr_freed_leaves_validate(mtr)); +} + +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +See btr_mark_freed_leaves(). */ + +ibool +btr_freed_leaves_validate( +/*======================*/ + /* out: TRUE if valid */ + mtr_t* mtr) /* in: mini-transaction */ +{ + ulint offset; + + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + ut_a(mtr->freed_clust_leaf); + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); + } + + return(TRUE); +} +#endif /* UNIV_DEBUG */ + /****************************************************************** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1015,7 +1199,7 @@ btr_root_raise_and_insert( a node pointer to the new page, and then splitting the new page. */ new_page = btr_page_alloc(index, 0, FSP_NO_DIR, - btr_page_get_level(root, mtr), mtr); + btr_page_get_level(root, mtr), mtr, mtr); btr_page_create(new_page, index, mtr); @@ -1636,7 +1820,7 @@ func_start: /* 2. Allocate a new page to the index */ new_page = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr); + btr_page_get_level(page, mtr), mtr, mtr); btr_page_create(new_page, cursor->index, mtr); /* 3. Calculate the first record on the upper half-page, and the diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 9ce09929f9a..a1dda8edf69 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2051,43 +2051,6 @@ return_after_reservations: return(err); } -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr) /* in/out: mini-transaction */ -{ - buf_block_t* block; - - block = buf_block_align(btr_cur_get_rec(cursor)); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); -#ifdef UNIV_SYNC_DEBUG - buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__); -#else - buf_block_buf_fix_inc(block); -#endif - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /******************************************************************** @@ -3494,6 +3457,11 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ + mtr_t* alloc_mtr, /* in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr containing the latch to rec and to the tree */ @@ -3514,6 +3482,8 @@ btr_store_big_rec_extern_fields( ulint i; mtr_t mtr; + ut_ad(local_mtr); + ut_ad(!alloc_mtr || alloc_mtr == local_mtr); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); @@ -3523,6 +3493,25 @@ btr_store_big_rec_extern_fields( space_id = buf_frame_get_space_id(rec); + if (alloc_mtr) { + /* Because alloc_mtr will be committed after + mtr, it is possible that the tablespace has been + extended when the B-tree record was updated or + inserted, or it will be extended while allocating + pages for big_rec. + + TODO: In mtr (not alloc_mtr), write a redo log record + about extending the tablespace to its current size, + and remember the current size. Whenever the tablespace + grows as pages are allocated, write further redo log + records to mtr. (Currently tablespace extension is not + covered by the redo log. If it were, the record would + only be written to alloc_mtr, which is committed after + mtr.) */ + } else { + alloc_mtr = &mtr; + } + /* We have to create a file segment to the tablespace for each field and put the pointer to the field in rec */ @@ -3549,7 +3538,7 @@ btr_store_big_rec_extern_fields( } page = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, &mtr); + FSP_NO_DIR, 0, alloc_mtr, &mtr); if (page == NULL) { mtr_commit(&mtr); @@ -3603,37 +3592,42 @@ btr_store_big_rec_extern_fields( extern_len -= store_len; + if (alloc_mtr == &mtr) { #ifdef UNIV_SYNC_DEBUG - rec_page = + rec_page = #endif /* UNIV_SYNC_DEBUG */ - buf_page_get(space_id, - buf_frame_get_page_no(data), - RW_X_LATCH, &mtr); + buf_page_get( + space_id, + buf_frame_get_page_no(data), + RW_X_LATCH, &mtr); #ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK); + buf_page_dbg_add_level( + rec_page, SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ + } + mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); if (prev_page_no == FIL_NULL) { mlog_write_ulint(data + local_len + BTR_EXTERN_SPACE_ID, space_id, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO, page_no, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); /* Set the bit denoting that this field in rec is stored externally */ @@ -3641,7 +3635,7 @@ btr_store_big_rec_extern_fields( rec_set_nth_field_extern_bit( rec, index, big_rec_vec->fields[i].field_no, - TRUE, &mtr); + TRUE, alloc_mtr); } prev_page_no = page_no; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 08e033e7a63..78b39812cff 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1008,29 +1008,6 @@ buf_page_peek_block( return(block); } -/************************************************************************ -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ - -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /* in: space id */ - ulint offset) /* in: page number */ -{ - buf_block_t* block; - - mutex_enter_fast(&(buf_pool->mutex)); - - block = buf_page_hash_get(space, offset); - - if (block) { - block->check_index_page_at_flush = FALSE; - } - - mutex_exit(&(buf_pool->mutex)); -} - /************************************************************************ Returns the current state of is_hashed of a page. FALSE if the page is not in the pool. NOTE that this operation does not fix the page in the diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index d228e683957..d5be8fca38f 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -293,15 +293,19 @@ fseg_alloc_free_page_low( /* out: the allocated page number, FIL_NULL if no page could be allocated */ ulint space, /* in: space */ - fseg_inode_t* seg_inode, /* in: segment inode */ + fseg_inode_t* seg_inode, /* in/out: segment inode */ ulint hint, /* in: hint of which page would be desirable */ byte direction, /* in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /* in: mtr handle */ - + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr);/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ /************************************************************************** Reads the file space size stored in the header page. */ @@ -1371,6 +1375,43 @@ fsp_alloc_free_extent( return(descr); } +/**********************************************************************//** +Allocates a single free page from a space. */ +static __attribute__((nonnull)) +void +fsp_alloc_from_free_frag( +/*=====================*/ + fsp_header_t* header, /* in/out: tablespace header */ + xdes_t* descr, /* in/out: extent descriptor */ + ulint bit, /* in: slot to allocate in the extent */ + mtr_t* mtr) /* in/out: mini-transaction */ +{ + ulint frag_n_used; + + ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); + xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } +} + /************************************************************************** Allocates a single free page from a space. The page is marked as used. */ static @@ -1381,19 +1422,22 @@ fsp_alloc_free_page( be allocated */ ulint space, /* in: space id */ ulint hint, /* in: hint of which page would be desirable */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr)/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr) */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; page_t* page; ulint free; - ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); + ut_ad(init_mtr); header = fsp_get_space_header(space, mtr); @@ -1441,6 +1485,7 @@ fsp_alloc_free_page( if (free == ULINT_UNDEFINED) { ut_print_buf(stderr, ((byte*)descr) - 500, 1000); + putc('\n', stderr); ut_error; } @@ -1472,40 +1517,21 @@ fsp_alloc_free_page( } } - xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } + fsp_alloc_from_free_frag(header, descr, free, mtr); /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, mtr); + buf_page_create(space, page_no, init_mtr); - page = buf_page_get(space, page_no, RW_X_LATCH, mtr); + page = buf_page_get(space, page_no, RW_X_LATCH, init_mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ /* Prior contents of the page should be ignored */ - fsp_init_file_page(page, mtr); + fsp_init_file_page(page, init_mtr); return(page_no); } @@ -1724,7 +1750,7 @@ fsp_alloc_seg_inode_page( space = buf_frame_get_space_id(space_header); - page_no = fsp_alloc_free_page(space, 0, mtr); + page_no = fsp_alloc_free_page(space, 0, mtr, mtr); if (page_no == FIL_NULL) { @@ -2094,7 +2120,8 @@ fseg_create_general( } if (page == 0) { - page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr); + page = fseg_alloc_free_page_low(space, + inode, 0, FSP_UP, mtr, mtr); if (page == FIL_NULL) { @@ -2331,14 +2358,19 @@ fseg_alloc_free_page_low( /* out: the allocated page number, FIL_NULL if no page could be allocated */ ulint space, /* in: space */ - fseg_inode_t* seg_inode, /* in: segment inode */ + fseg_inode_t* seg_inode, /* in/out: segment inode */ ulint hint, /* in: hint of which page would be desirable */ byte direction, /* in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr)/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ { fsp_header_t* space_header; ulint space_size; @@ -2350,7 +2382,6 @@ fseg_alloc_free_page_low( if could not be allocated */ xdes_t* ret_descr; /* the extent of the allocated page */ page_t* page; - ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2371,6 +2402,8 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ + ut_a(init_mtr); + /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, hint, mtr); } @@ -2382,15 +2415,20 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { - +take_hinted_page: /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; + /* Skip the check for extending the tablespace. If the + page hint were not within the size of the tablespace, + we would have got (descr == NULL) above and reset the hint. */ + goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if ((xdes_get_state(descr, mtr) == XDES_FREE) - && ((reserved - used) < reserved / FSEG_FILLFACTOR) - && (used >= FSEG_FRAG_LIMIT)) { + } else if (xdes_get_state(descr, mtr) == XDES_FREE + && (!init_mtr + || ((reserved - used < reserved / FSEG_FILLFACTOR) + && used >= FSEG_FRAG_LIMIT))) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2408,8 +2446,20 @@ fseg_alloc_free_page_low( /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, hint + FSP_EXTENT_SIZE, mtr); - ret_page = hint; + goto take_hinted_page; /*-----------------------------------------------------------*/ + } else if (!init_mtr) { + ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + fsp_alloc_from_free_frag(space_header, descr, + hint % FSP_EXTENT_SIZE, mtr); + ret_page = hint; + ret_descr = NULL; + + /* Put the page in the fragment page array of the segment */ + n = fseg_find_free_frag_page_slot(seg_inode, mtr); + ut_a(n != FIL_NULL); + fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); + goto got_hinted_page; } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2467,11 +2517,9 @@ fseg_alloc_free_page_low( } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, hint, mtr); + ret_page = fsp_alloc_free_page(space, hint, mtr, init_mtr); ret_descr = NULL; - frag_page_allocated = TRUE; - if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2481,6 +2529,10 @@ fseg_alloc_free_page_low( fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } + + /* fsp_alloc_free_page() invoked fsp_init_file_page() + already. */ + return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2527,22 +2579,31 @@ fseg_alloc_free_page_low( } } - if (!frag_page_allocated) { +got_hinted_page: + { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ + mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - page = buf_page_create(space, ret_page, mtr); + page = buf_page_create(space, ret_page, block_mtr); - ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr)); + ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, + block_mtr)); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ - /* The prior contents of the page should be ignored */ - fsp_init_file_page(page, mtr); + if (init_mtr) { + /* The prior contents of the page should be ignored */ + fsp_init_file_page(page, init_mtr); + } + } + /* ret_descr == NULL if the block was allocated from free_frag + (XDES_FREE_FRAG) */ + if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2554,8 +2615,6 @@ fseg_alloc_free_page_low( fseg_mark_page_used(seg_inode, space, ret_page, mtr); } - buf_reset_check_index_page_at_flush(space, ret_page); - return(ret_page); } @@ -2569,7 +2628,7 @@ fseg_alloc_free_page_general( /*=========================*/ /* out: allocated page offset, FIL_NULL if no page could be allocated */ - fseg_header_t* seg_header,/* in: segment header */ + fseg_header_t* seg_header,/* in/out: segment header */ ulint hint, /* in: hint of which page would be desirable */ byte direction,/* in: if the new page is needed because of an index page split, and records are @@ -2581,7 +2640,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction handle */ + mtr_t* init_mtr)/* in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ { fseg_inode_t* inode; ulint space; @@ -2619,7 +2682,8 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode), - inode, hint, direction, mtr); + inode, hint, direction, + mtr, init_mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2647,7 +2711,7 @@ fseg_alloc_free_page( mtr_t* mtr) /* in: mtr handle */ { return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr)); + FALSE, mtr, mtr)); } /************************************************************************** diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 269fa355558..3988019589d 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -379,7 +379,11 @@ btr_page_alloc( page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr); /* in: mtr */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr); /* in/out: mini-transaction + for x-latching and initializing + the page */ /****************************************************************** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -402,6 +406,31 @@ btr_page_free_low( page_t* page, /* in: page to be freed, x-latched */ ulint level, /* in: page level */ mtr_t* mtr); /* in: mtr */ +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ + +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /* in/out: clustered index */ + mtr_t* mtr, /* in/out: mini-transaction */ + ibool nonfree);/* in: TRUE=mark nonfree, FALSE=mark freed */ +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +See btr_mark_freed_leaves(). */ + +ibool +btr_freed_leaves_validate( +/*======================*/ + /* out: TRUE if valid */ + mtr_t* mtr); /* in: mini-transaction */ +#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /***************************************************************** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index c068d8d3318..c2bf84ef9cb 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -252,15 +252,6 @@ btr_cur_pessimistic_update( updates */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr); /* in: mtr */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr); /* in/out: mini-transaction */ /*************************************************************** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -471,6 +462,11 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ + mtr_t* alloc_mtr, /* in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ mtr_t* local_mtr); /* in: mtr containing the latch to rec and to the tree */ /*********************************************************************** diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7479ce9cbf0..87b2f6172de 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -294,15 +294,6 @@ buf_page_peek_block( ulint space, /* in: space id */ ulint offset);/* in: page number */ /************************************************************************ -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ - -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /* in: space id */ - ulint offset);/* in: page number */ -/************************************************************************ Sets file_page_was_freed TRUE if the page is found in the buffer pool. This function should be called when we free a file page and want the debug version to check that it is not accessed any more unless diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 17bfbeec2c1..4c58d6075e6 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -167,7 +167,7 @@ fseg_alloc_free_page_general( /*=========================*/ /* out: allocated page offset, FIL_NULL if no page could be allocated */ - fseg_header_t* seg_header,/* in: segment header */ + fseg_header_t* seg_header,/* in/out: segment header */ ulint hint, /* in: hint of which page would be desirable */ byte direction,/* in: if the new page is needed because of an index page split, and records are @@ -179,7 +179,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr); /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr);/* in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ /************************************************************************** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index a6e2976830b..a0a51dbbd17 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -36,6 +36,8 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 +/* The mini-transaction freed a clustered index leaf page. */ +#define MTR_MEMO_FREE_CLUST_LEAF 57 /* Log item types: we have made them to be of the type 'byte' for the compiler to warn if val and type parameters are switched @@ -325,9 +327,12 @@ struct mtr_struct{ ulint state; /* MTR_ACTIVE, MTR_COMMITTING, MTR_COMMITTED */ dyn_array_t memo; /* memo stack for locks etc. */ dyn_array_t log; /* mini-transaction log */ - ibool modifications; + unsigned modifications:1; /* TRUE if the mtr made modifications to buffer pool pages */ + unsigned freed_clust_leaf:1; + /* TRUE if MTR_MEMO_FREE_CLUST_LEAF + was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 81eec3bfc92..6b4cacf0766 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -26,6 +26,7 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; + mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; #ifdef UNIV_DEBUG @@ -50,7 +51,8 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_X_LOCK); + ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 365fa15878a..a11e20ca661 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -53,17 +53,13 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); -#ifdef UNIV_DEBUG - } else if (type == MTR_MEMO_X_LOCK) { - rw_lock_x_unlock((rw_lock_t*)object); - } else { - ut_ad(type == MTR_MEMO_MODIFY); + } else if (type != MTR_MEMO_X_LOCK) { + ut_ad(type == MTR_MEMO_MODIFY + || type == MTR_MEMO_FREE_CLUST_LEAF); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); -#else } else { rw_lock_x_unlock((rw_lock_t*)object); -#endif } } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 7ff443a11ad..6366beb6b47 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -2089,15 +2089,20 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); + columns, but allocate the pages and + write the pointers using the + mini-transaction of the record update. + If any pages were freed in the update, + temporarily mark them allocated so + that off-page columns will not + overwrite them. We must do this, + because we will write the redo log for + the BLOB writes before writing the + redo log for the record update. Thus, + redo log application at crash recovery + will see BLOBs being written to free pages. */ + + btr_mark_freed_leaves(index, &mtr, TRUE); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(rec, index, offsets, @@ -2105,7 +2110,8 @@ row_ins_index_entry_low( &heap); err = btr_store_big_rec_extern_fields( - index, rec, offsets, big_rec, &mtr); + index, rec, offsets, big_rec, + &mtr, &mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2118,6 +2124,9 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again + in order to avoid a leak. */ + btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2165,7 +2174,8 @@ function_exit: ULINT_UNDEFINED, &heap); err = btr_store_big_rec_extern_fields(index, rec, - offsets, big_rec, &mtr); + offsets, big_rec, + NULL, &mtr); stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 171039e34ac..ccb3c1f7781 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -212,23 +212,27 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - /* This condition can occur during crash recovery before - trx_rollback_or_clean_all_without_sess() has completed - execution. + if (rec_offs_any_null_extern(rec, offsets)) { + /* This condition can occur during crash recovery + before trx_rollback_or_clean_all_without_sess() has + completed execution. - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it is active. (In this version of InnoDB, we - cannot assert that it was recovered, because there is no - trx->is_recovered field.) */ + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it is active. (In this version of InnoDB, we + cannot assert that it was recovered, because there is no + trx->is_recovered field.) */ - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_assert_active(row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_assert_active( + row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_undo_roll_ptr_is_insert( + row_get_rec_roll_ptr(rec, index, offsets))); + } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 694b00ea265..58739edfd98 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1591,21 +1591,22 @@ row_upd_clust_rec( *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + /* Write out the externally stored columns, but + allocate the pages and write the pointers using the + mini-transaction of the record update. If any pages + were freed in the update, temporarily mark them + allocated so that off-page columns will not overwrite + them. We must do this, because we write the redo log + for the BLOB writes before writing the redo log for + the record update. */ + btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr); + big_rec, mtr, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -1618,6 +1619,8 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again in order to avoid a leak. */ + btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 329565943c8..ce09862f317 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -864,7 +864,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr); + TRUE, mtr, mtr); fil_space_release_free_extents(undo->space, n_reserved); diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 0b90b5729d5..96b6a47085a 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,17 @@ +2011-08-29 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, + include/btr0btr.h, include/btr0cur.h, include/fsp0fsp.h, + include/mtr0mtr.h, include/mtr0mtr.ic, mtr/mtr0mtr.c, + row/row0ins.c, row/row0row.c, row/row0upd.c, trx/trx0undo.c: + Fix Bug#12704861 Corruption after a crash during BLOB update + and other regressions from the fix of Bug#12612184 + +2011-08-23 The InnoDB Team + + * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: + Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE + 2011-08-15 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 5e6724bbd54..71e1599d19e 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -906,28 +906,29 @@ btr_page_alloc_for_ibuf( /**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! -@return new allocated block, x-latched; NULL if out of space */ -UNIV_INTERN -buf_block_t* -btr_page_alloc( -/*===========*/ +@return allocated page number, FIL_NULL if out of space */ +static __attribute__((nonnull(1,5), warn_unused_result)) +ulint +btr_page_alloc_low( +/*===============*/ dict_index_t* index, /*!< in: index */ ulint hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + in which the page should be + initialized (may be the same + as mtr), or NULL if it should + not be initialized (the page + at hint was previously freed + in mtr) */ { fseg_header_t* seg_header; page_t* root; - buf_block_t* new_block; - ulint new_page_no; - - if (dict_index_is_ibuf(index)) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } root = btr_root_get(index, mtr); @@ -941,8 +942,42 @@ btr_page_alloc( reservation for free extents, and thus we know that a page can be allocated: */ - new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, mtr); + return(fseg_alloc_free_page_general( + seg_header, hint_page_no, file_direction, + TRUE, mtr, init_mtr)); +} + +/**************************************************************//** +Allocates a new file page to be used in an index tree. NOTE: we assume +that the caller has made the reservation for free extents! +@return new allocated block, x-latched; NULL if out of space */ +UNIV_INTERN +buf_block_t* +btr_page_alloc( +/*===========*/ + dict_index_t* index, /*!< in: index */ + ulint hint_page_no, /*!< in: hint of a good page */ + byte file_direction, /*!< in: direction where a possible + page split is made */ + ulint level, /*!< in: level where the page is placed + in the tree */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + for x-latching and initializing + the page */ +{ + buf_block_t* new_block; + ulint new_page_no; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } + + new_page_no = btr_page_alloc_low( + index, hint_page_no, file_direction, level, mtr, init_mtr); + if (new_page_no == FIL_NULL) { return(NULL); @@ -950,9 +985,16 @@ btr_page_alloc( new_block = buf_page_get(dict_index_get_space(index), dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, mtr); + new_page_no, RW_X_LATCH, init_mtr); buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + if (mtr->freed_clust_leaf) { + mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(!mtr_memo_contains(mtr, new_block, + MTR_MEMO_FREE_CLUST_LEAF)); + } + + ut_ad(btr_freed_leaves_validate(mtr)); return(new_block); } @@ -1065,6 +1107,15 @@ btr_page_free_low( fseg_free_page(seg_header, buf_block_get_space(block), buf_block_get_page_no(block), mtr); + + /* The page was marked free in the allocation bitmap, but it + should remain buffer-fixed until mtr_commit(mtr) or until it + is explicitly freed from the mini-transaction. */ + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + /* TODO: Discard any operations on the page from the redo log + and remove the block from the flush list and the buffer pool. + This would free up buffer pool earlier and reduce writes to + both the tablespace and the redo log. */ } /**************************************************************//** @@ -1078,13 +1129,140 @@ btr_page_free( buf_block_t* block, /*!< in: block to be freed, x-latched */ mtr_t* mtr) /*!< in: mtr */ { - ulint level; - - level = btr_page_get_level(buf_block_get_frame(block), mtr); + const page_t* page = buf_block_get_frame(block); + ulint level = btr_page_get_level(page, mtr); + ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX); btr_page_free_low(index, block, level, mtr); + + /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + + if (level == 0 && dict_index_is_clust(index)) { + /* We may have to call btr_mark_freed_leaves() to + temporarily mark the block nonfree for invoking + btr_store_big_rec_extern_fields_func() after an + update. Remember that the block was freed. */ + mtr->freed_clust_leaf = TRUE; + mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF); + } + + ut_ad(btr_freed_leaves_validate(mtr)); } +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ +UNIV_INTERN +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /*!< in/out: clustered index */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ +{ + /* This is loosely based on mtr_memo_release(). */ + + ulint offset; + + ut_ad(dict_index_is_clust(index)); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + if (!mtr->freed_clust_leaf) { + return; + } + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(buf_block_get_space(block) + == dict_index_get_space(index)); + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(page_is_leaf(buf_block_get_frame(block))); + + if (nonfree) { + /* Allocate the same page again. */ + ulint page_no; + page_no = btr_page_alloc_low( + index, buf_block_get_page_no(block), + FSP_NO_DIR, 0, mtr, NULL); + ut_a(page_no == buf_block_get_page_no(block)); + } else { + /* Assert that the page is allocated and free it. */ + btr_page_free_low(index, block, 0, mtr); + } + } + + ut_ad(btr_freed_leaves_validate(mtr)); +} + +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +@see btr_mark_freed_leaves() +@return TRUE */ +UNIV_INTERN +ibool +btr_freed_leaves_validate( +/*======================*/ + mtr_t* mtr) /*!< in: mini-transaction */ +{ + ulint offset; + + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + const mtr_memo_slot_t* slot; + const buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + ut_a(mtr->freed_clust_leaf); + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(page_is_leaf(buf_block_get_frame(block))); + } + + return(TRUE); +} +#endif /* UNIV_DEBUG */ + /**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1806,7 +1984,7 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr); + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2542,7 +2720,7 @@ func_start: /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr); + btr_page_get_level(page, mtr), mtr, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 5cefa51bcd5..f1c2c2ddd5e 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -2414,39 +2414,6 @@ return_after_reservations: return(err); } -/**************************************************************//** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - buf_block_t* block; - - block = btr_cur_get_block(cursor); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /****************************************************************//** @@ -3901,6 +3868,9 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ + const big_rec_t*big_rec_vec, /*!< in: vector containing fields + to be stored externally */ + #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -3909,9 +3879,11 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - const big_rec_t*big_rec_vec) /*!< in: vector containing fields - to be stored externally */ - + mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ { ulint rec_page_no; byte* field_ref; @@ -3930,6 +3902,9 @@ btr_store_big_rec_extern_fields_func( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); + ut_ad(local_mtr); + ut_ad(!alloc_mtr || alloc_mtr == local_mtr); + ut_ad(!update_in_place || alloc_mtr); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -3945,6 +3920,25 @@ btr_store_big_rec_extern_fields_func( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); + if (alloc_mtr) { + /* Because alloc_mtr will be committed after + mtr, it is possible that the tablespace has been + extended when the B-tree record was updated or + inserted, or it will be extended while allocating + pages for big_rec. + + TODO: In mtr (not alloc_mtr), write a redo log record + about extending the tablespace to its current size, + and remember the current size. Whenever the tablespace + grows as pages are allocated, write further redo log + records to mtr. (Currently tablespace extension is not + covered by the redo log. If it were, the record would + only be written to alloc_mtr, which is committed after + mtr.) */ + } else { + alloc_mtr = &mtr; + } + if (UNIV_LIKELY_NULL(page_zip)) { int err; @@ -4021,7 +4015,7 @@ btr_store_big_rec_extern_fields_func( } block = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, &mtr); + FSP_NO_DIR, 0, alloc_mtr, &mtr); if (UNIV_UNLIKELY(block == NULL)) { mtr_commit(&mtr); @@ -4148,11 +4142,15 @@ btr_store_big_rec_extern_fields_func( goto next_zip_page; } - rec_block = buf_page_get(space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(rec_block, - SYNC_NO_ORDER_CHECK); + if (alloc_mtr == &mtr) { + rec_block = buf_page_get( + space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level( + rec_block, + SYNC_NO_ORDER_CHECK); + } if (err == Z_STREAM_END) { mach_write_to_4(field_ref @@ -4186,7 +4184,8 @@ btr_store_big_rec_extern_fields_func( page_zip_write_blob_ptr( page_zip, rec, index, offsets, - big_rec_vec->fields[i].field_no, &mtr); + big_rec_vec->fields[i].field_no, + alloc_mtr); next_zip_page: prev_page_no = page_no; @@ -4231,19 +4230,23 @@ next_zip_page: extern_len -= store_len; - rec_block = buf_page_get(space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(rec_block, - SYNC_NO_ORDER_CHECK); + if (alloc_mtr == &mtr) { + rec_block = buf_page_get( + space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level( + rec_block, + SYNC_NO_ORDER_CHECK); + } mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); if (prev_page_no == FIL_NULL) { btr_blob_dbg_add_blob( @@ -4253,18 +4256,19 @@ next_zip_page: mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, - space_id, - MLOG_4BYTES, &mtr); + space_id, MLOG_4BYTES, + alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO, - page_no, - MLOG_4BYTES, &mtr); + page_no, MLOG_4BYTES, + alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, + alloc_mtr); } prev_page_no = page_no; diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index cd1461d22b7..47300627acc 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1174,29 +1174,6 @@ buf_page_set_accessed_make_young( } } -/********************************************************************//** -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ -UNIV_INTERN -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: page number */ -{ - buf_block_t* block; - - buf_pool_mutex_enter(); - - block = (buf_block_t*) buf_page_hash_get(space, offset); - - if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) { - block->check_index_page_at_flush = FALSE; - } - - buf_pool_mutex_exit(); -} - /********************************************************************//** Returns the current state of is_hashed of a page. FALSE if the page is not in the pool. NOTE that this operation does not fix the page in the diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index d091a14c474..19846b63d5b 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, 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 @@ -312,8 +312,9 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr); /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -326,14 +327,20 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in: segment inode */ + fseg_inode_t* seg_inode, /*!< in/out: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ + __attribute__((warn_unused_result, nonnull(3,6))); #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -701,17 +708,18 @@ list, if not free limit == space size. This adding is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -UNIV_INLINE +UNIV_INLINE __attribute__((nonnull, warn_unused_result)) xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ - ulint space, /*!< in: space id */ - ulint offset, /*!< in: page offset; - if equal to the free limit, - we try to add new extents to - the space free list */ - mtr_t* mtr) /*!< in: mtr handle */ + fsp_header_t* sp_header, /*!< in/out: space header, x-latched + in mtr */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page offset; if equal + to the free limit, we try to + add new extents to the space + free list */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint limit; ulint size; @@ -719,11 +727,9 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; - ut_ad(mtr); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX) - || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -773,7 +779,7 @@ is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -static +static __attribute__((nonnull, warn_unused_result)) xdes_t* xdes_get_descriptor( /*================*/ @@ -782,7 +788,7 @@ xdes_get_descriptor( or 0 for uncompressed pages */ ulint offset, /*!< in: page offset; if equal to the free limit, we try to add new extents to the space free list */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; fsp_header_t* sp_header; @@ -1160,14 +1166,14 @@ fsp_header_get_tablespace_size(void) Tries to extend a single-table tablespace so that a page would fit in the data file. @return TRUE if success */ -static +static __attribute__((nonnull, warn_unused_result)) ibool fsp_try_extend_data_file_with_pages( /*================================*/ ulint space, /*!< in: space */ ulint page_no, /*!< in: page number */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr) /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ibool success; ulint actual_size; @@ -1192,7 +1198,7 @@ fsp_try_extend_data_file_with_pages( /***********************************************************************//** Tries to extend the last data file of a tablespace if it is auto-extending. @return FALSE if not auto-extending */ -static +static __attribute__((nonnull)) ibool fsp_try_extend_data_file( /*=====================*/ @@ -1202,8 +1208,8 @@ fsp_try_extend_data_file( the actual file size rounded down to megabyte */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr) /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint size; ulint zip_size; @@ -1339,7 +1345,7 @@ fsp_fill_free_list( then we do not allocate more extents */ ulint space, /*!< in: space */ fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint limit; ulint size; @@ -1537,10 +1543,47 @@ fsp_alloc_free_extent( return(descr); } +/**********************************************************************//** +Allocates a single free page from a space. */ +static __attribute__((nonnull)) +void +fsp_alloc_from_free_frag( +/*=====================*/ + fsp_header_t* header, /*!< in/out: tablespace header */ + xdes_t* descr, /*!< in/out: extent descriptor */ + ulint bit, /*!< in: slot to allocate in the extent */ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + ulint frag_n_used; + + ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); + xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } +} + /**********************************************************************//** Allocates a single free page from a space. The page is marked as used. @return the page offset, FIL_NULL if no page could be allocated */ -static +static __attribute__((nonnull, warn_unused_result)) ulint fsp_alloc_free_page( /*================*/ @@ -1548,19 +1591,22 @@ fsp_alloc_free_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint hint, /*!< in: hint of which page would be desirable */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr) */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; buf_block_t* block; ulint free; - ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); + ut_ad(init_mtr); header = fsp_get_space_header(space, zip_size, mtr); @@ -1642,38 +1688,19 @@ fsp_alloc_free_page( } } - xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } + fsp_alloc_from_free_frag(header, descr, free, mtr); /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, zip_size, mtr); + buf_page_create(space, page_no, zip_size, init_mtr); - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); + block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); + fsp_init_file_page(block, init_mtr); return(page_no); } @@ -1909,7 +1936,7 @@ fsp_alloc_seg_inode_page( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - page_no = fsp_alloc_free_page(space, zip_size, 0, mtr); + page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); if (page_no == FIL_NULL) { @@ -2323,7 +2350,7 @@ fseg_create_general( if (page == 0) { page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr); + inode, 0, FSP_UP, mtr, mtr); if (page == FIL_NULL) { @@ -2572,14 +2599,19 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in: segment inode */ + fseg_inode_t* seg_inode, /*!< in/out: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ { fsp_header_t* space_header; ulint space_size; @@ -2590,7 +2622,6 @@ fseg_alloc_free_page_low( ulint ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ - ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2612,6 +2643,8 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ + ut_a(init_mtr); + /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2623,15 +2656,20 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { - +take_hinted_page: /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; + /* Skip the check for extending the tablespace. If the + page hint were not within the size of the tablespace, + we would have got (descr == NULL) above and reset the hint. */ + goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if ((xdes_get_state(descr, mtr) == XDES_FREE) - && ((reserved - used) < reserved / FSEG_FILLFACTOR) - && (used >= FSEG_FRAG_LIMIT)) { + } else if (xdes_get_state(descr, mtr) == XDES_FREE + && (!init_mtr + || ((reserved - used < reserved / FSEG_FILLFACTOR) + && used >= FSEG_FRAG_LIMIT))) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2649,8 +2687,20 @@ fseg_alloc_free_page_low( /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, zip_size, hint + FSP_EXTENT_SIZE, mtr); - ret_page = hint; + goto take_hinted_page; /*-----------------------------------------------------------*/ + } else if (!init_mtr) { + ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + fsp_alloc_from_free_frag(space_header, descr, + hint % FSP_EXTENT_SIZE, mtr); + ret_page = hint; + ret_descr = NULL; + + /* Put the page in the fragment page array of the segment */ + n = fseg_find_free_frag_page_slot(seg_inode, mtr); + ut_a(n != FIL_NULL); + fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); + goto got_hinted_page; } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2710,11 +2760,10 @@ fseg_alloc_free_page_low( } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr); + ret_page = fsp_alloc_free_page(space, zip_size, hint, + mtr, init_mtr); ret_descr = NULL; - frag_page_allocated = TRUE; - if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2724,6 +2773,10 @@ fseg_alloc_free_page_low( fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } + + /* fsp_alloc_free_page() invoked fsp_init_file_page() + already. */ + return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2771,26 +2824,34 @@ fseg_alloc_free_page_low( } } - if (!frag_page_allocated) { +got_hinted_page: + { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ buf_block_t* block; ulint zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); + mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - block = buf_page_create(space, ret_page, zip_size, mtr); + block = buf_page_create(space, ret_page, zip_size, block_mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size, ret_page, RW_X_LATCH, - mtr))) { + block_mtr))) { ut_error; } - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); + if (init_mtr) { + /* The prior contents of the page should be ignored */ + fsp_init_file_page(block, init_mtr); + } + } + /* ret_descr == NULL if the block was allocated from free_frag + (XDES_FREE_FRAG) */ + if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2803,8 +2864,6 @@ fseg_alloc_free_page_low( fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr); } - buf_reset_check_index_page_at_flush(space, ret_page); - return(ret_page); } @@ -2817,7 +2876,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ + fseg_header_t* seg_header,/*!< in/out: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -2829,7 +2888,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction handle */ + mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ { fseg_inode_t* inode; ulint space; @@ -2871,7 +2934,8 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, mtr); + inode, hint, direction, + mtr, init_mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2879,28 +2943,6 @@ fseg_alloc_free_page_general( return(page_no); } -/**********************************************************************//** -Allocates a single free page from a segment. This function implements -the intelligent allocation strategy which tries to minimize file space -fragmentation. -@return allocated page offset, FIL_NULL if no page could be allocated */ -UNIV_INTERN -ulint -fseg_alloc_free_page( -/*=================*/ - fseg_header_t* seg_header,/*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ - byte direction,/*!< in: if the new page is needed because - of an index page split, and records are - inserted there in order, into which - direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /*!< in: mtr handle */ -{ - return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr)); -} - /**********************************************************************//** Checks that we have at least 2 frag pages free in the first extent of a single-table tablespace, and they are also physically initialized to the data diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index c0a038dd21d..476ad29adac 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -557,7 +557,12 @@ btr_page_alloc( page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr); /*!< in: mtr */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + for x-latching and initializing + the page */ + __attribute__((nonnull, warn_unused_result)); /**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -580,6 +585,33 @@ btr_page_free_low( buf_block_t* block, /*!< in: block to be freed, x-latched */ ulint level, /*!< in: page level */ mtr_t* mtr); /*!< in: mtr */ +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ +UNIV_INTERN +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /*!< in/out: clustered index */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +@see btr_mark_freed_leaves() +@return TRUE */ +UNIV_INTERN +ibool +btr_freed_leaves_validate( +/*======================*/ + mtr_t* mtr) /*!< in: mini-transaction */ + __attribute__((nonnull, warn_unused_result)); +#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /*************************************************************//** Prints size info of a B-tree. */ diff --git a/storage/innodb_plugin/include/btr0cur.h b/storage/innodb_plugin/include/btr0cur.h index 6094a2a6c7a..1d97c5b9452 100644 --- a/storage/innodb_plugin/include/btr0cur.h +++ b/storage/innodb_plugin/include/btr0cur.h @@ -326,16 +326,6 @@ btr_cur_pessimistic_update( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr; must be committed before latching any further pages */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); /***********************************************************//** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -540,6 +530,8 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ + const big_rec_t*big_rec_vec, /*!< in: vector containing fields + to be stored externally */ #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -548,9 +540,12 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - const big_rec_t*big_rec_vec) /*!< in: vector containing fields - to be stored externally */ - __attribute__((nonnull)); + mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ + __attribute__((nonnull(1,2,3,4,5), warn_unused_result)); /** Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. @@ -559,21 +554,22 @@ file segment of the index tree. @param index in: clustered index; MUST be X-latched by mtr @param b in/out: block containing rec; MUST be X-latched by mtr @param rec in/out: clustered index record -@param offsets in: rec_get_offsets(rec, index); +@param offs in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not be adjusted +@param big in: vector containing fields to be stored externally @param mtr in: mini-transaction that holds x-latch on index and b @param upd in: TRUE if the record is updated in place (not delete+insert) -@param big in: vector containing fields to be stored externally +@param rmtr in/out: in updates, the mini-transaction that holds rec @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ #ifdef UNIV_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr) #elif defined UNIV_BLOB_LIGHT_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr) #else -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr) #endif /*******************************************************************//** diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 9856bfce409..557bc17d311 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -372,15 +372,6 @@ buf_page_peek( /*==========*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: page number */ -/********************************************************************//** -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ -UNIV_INTERN -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: page number */ #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. diff --git a/storage/innodb_plugin/include/fsp0fsp.h b/storage/innodb_plugin/include/fsp0fsp.h index 7abd3914eda..2221380c9a2 100644 --- a/storage/innodb_plugin/include/fsp0fsp.h +++ b/storage/innodb_plugin/include/fsp0fsp.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 @@ -176,19 +176,18 @@ fseg_n_reserved_pages( Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space fragmentation. -@return the allocated page offset FIL_NULL if no page could be allocated */ -UNIV_INTERN -ulint -fseg_alloc_free_page( -/*=================*/ - fseg_header_t* seg_header, /*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ - byte direction, /*!< in: if the new page is needed because +@param[in/out] seg_header segment header +@param[in] hint hint of which page would be desirable +@param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /*!< in: mtr handle */ + FSP_UP, FSP_NO_DIR +@param[in/out] mtr mini-transaction +@return the allocated page offset FIL_NULL if no page could be allocated */ +#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \ + fseg_alloc_free_page_general(seg_header, hint, direction, \ + FALSE, mtr, mtr) /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -198,7 +197,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ + fseg_header_t* seg_header,/*!< in/out: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -210,7 +209,12 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr); /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ + __attribute__((warn_unused_result, nonnull(1,5))); /**********************************************************************//** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index bc3f1951be9..2a561131c09 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 @@ -53,6 +53,8 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 +/** The mini-transaction freed a clustered index leaf page. */ +#define MTR_MEMO_FREE_CLUST_LEAF 57 /** @name Log item types The log items are declared 'byte' so that the compiler can warn if val @@ -387,9 +389,12 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ - ibool modifications; - /* TRUE if the mtr made modifications to - buffer pool pages */ + unsigned modifications:1; + /*!< TRUE if the mini-transaction + modified buffer pool pages */ + unsigned freed_clust_leaf:1; + /*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF + was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innodb_plugin/include/mtr0mtr.ic b/storage/innodb_plugin/include/mtr0mtr.ic index 18f8e87b3cf..9c0ddff9132 100644 --- a/storage/innodb_plugin/include/mtr0mtr.ic +++ b/storage/innodb_plugin/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, 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 @@ -44,6 +44,7 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; + mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); @@ -67,7 +68,8 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_X_LOCK); + ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); diff --git a/storage/innodb_plugin/include/trx0undo.h b/storage/innodb_plugin/include/trx0undo.h index 4f15cd85833..c95f99d6417 100644 --- a/storage/innodb_plugin/include/trx0undo.h +++ b/storage/innodb_plugin/include/trx0undo.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, 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 @@ -204,17 +204,51 @@ trx_undo_add_page( mtr_t* mtr); /*!< in: mtr which does not have a latch to any undo log page; the caller must have reserved the rollback segment mutex */ +/********************************************************************//** +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN +void +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(trx,undo,mtr) +#else /* UNIV_DEBUG */ +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(undo,mtr) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ - trx_undo_t* undo, /*!< in: undo log */ - undo_no_t limit); /*!< in: all undo records with undo number +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log */ + undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(trx,undo,limit) +#else /* UNIV_DEBUG */ +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(undo,limit) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the start. This function is used during a purge operation. */ diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index 417e97732bb..6dd5b6eb8c3 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 @@ -58,12 +58,11 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); -#ifdef UNIV_DEBUG } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY); + ut_ad(type == MTR_MEMO_MODIFY + || type == MTR_MEMO_FREE_CLUST_LEAF); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); -#endif /* UNIV_DEBUG */ } else { rw_lock_x_unlock((rw_lock_t*)object); } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index ea43cbfb5f1..0f158cdc706 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -2094,15 +2094,20 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); + columns, but allocate the pages and + write the pointers using the + mini-transaction of the record update. + If any pages were freed in the update, + temporarily mark them allocated so + that off-page columns will not + overwrite them. We must do this, + because we will write the redo log for + the BLOB writes before writing the + redo log for the record update. Thus, + redo log application at crash recovery + will see BLOBs being written to free pages. */ + + btr_mark_freed_leaves(index, &mtr, TRUE); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets( @@ -2111,7 +2116,8 @@ row_ins_index_entry_low( err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, + FALSE, &mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2124,6 +2130,9 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again + in order to avoid a leak. */ + btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2165,7 +2174,7 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, FALSE, NULL); stored_big_rec: if (modify) { diff --git a/storage/innodb_plugin/row/row0row.c b/storage/innodb_plugin/row/row0row.c index 9cdbbe76e04..e476ffae84e 100644 --- a/storage/innodb_plugin/row/row0row.c +++ b/storage/innodb_plugin/row/row0row.c @@ -243,19 +243,20 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - /* This condition can occur during crash recovery before - trx_rollback_active() has completed execution. + if (rec_offs_any_null_extern(rec, offsets)) { + /* This condition can occur during crash recovery + before trx_rollback_active() has completed execution. - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. - - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it was recovered (and will soon be rolled back). */ - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_assert_recovered(row_get_rec_trx_id(rec, index, offsets))); + This condition is possible if the server crashed + during an insert or update-by-delete-and-insert before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the freshly inserted clustered index + record. */ + ut_a(trx_assert_recovered( + row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_undo_roll_ptr_is_insert( + row_get_rec_roll_ptr(rec, index, offsets))); + } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index b5952ff0a78..05856687015 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -1978,21 +1978,22 @@ row_upd_clust_rec( rec_offs_init(offsets_); ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + /* Write out the externally stored columns, but + allocate the pages and write the pointers using the + mini-transaction of the record update. If any pages + were freed in the update, temporarily mark them + allocated so that off-page columns will not overwrite + them. We must do this, because we write the redo log + for the BLOB writes before writing the redo log for + the record update. */ + btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - mtr, TRUE, big_rec); + big_rec, mtr, TRUE, mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if we did not update any externally stored @@ -2002,6 +2003,8 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again in order to avoid a leak. */ + btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index 9f2fd59d82b..a729a39d0cc 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1097,22 +1097,29 @@ trx_undo_rec_get_partial_row( #endif /* !UNIV_HOTBACKUP */ /***********************************************************************//** -Erases the unused undo log page end. */ -static -void +Erases the unused undo log page end. +@return TRUE if the page contained something, FALSE if it was empty */ +static __attribute__((nonnull, warn_unused_result)) +ibool trx_undo_erase_page_end( /*====================*/ - page_t* undo_page, /*!< in: undo page whose end to erase */ - mtr_t* mtr) /*!< in: mtr */ + page_t* undo_page, /*!< in/out: undo page whose end to erase */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint first_free; first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); + if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { + /* This was an empty page to begin with. + Do nothing here; the caller should free the page. */ + return(FALSE); + } memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); + return(TRUE); } /***********************************************************//** @@ -1134,7 +1141,11 @@ trx_undo_parse_erase_page_end( return(ptr); } - trx_undo_erase_page_end(page, mtr); + if (!trx_undo_erase_page_end(page, mtr)) { + /* The function trx_undo_erase_page_end() should not + have done anything to an empty page. */ + ut_ad(0); + } return(ptr); } @@ -1180,6 +1191,9 @@ trx_undo_report_row_operation( mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; +#ifdef UNIV_DEBUG + int loop_count = 0; +#endif /* UNIV_DEBUG */ rec_offs_init(offsets_); ut_a(dict_index_is_clust(index)); @@ -1242,7 +1256,7 @@ trx_undo_report_row_operation( mtr_start(&mtr); - for (;;) { + do { buf_block_t* undo_block; page_t* undo_page; ulint offset; @@ -1271,7 +1285,19 @@ trx_undo_report_row_operation( version the replicate page constructed using the log records stays identical to the original page */ - trx_undo_erase_page_end(undo_page, &mtr); + if (!trx_undo_erase_page_end(undo_page, &mtr)) { + /* The record did not fit on an empty + undo page. Discard the freshly allocated + page and return an error. */ + + mutex_enter(&rseg->mutex); + trx_undo_free_last_page(trx, undo, &mtr); + mutex_exit(&rseg->mutex); + + err = DB_TOO_BIG_RECORD; + goto err_exit; + } + mtr_commit(&mtr); } else { /* Success */ @@ -1291,16 +1317,15 @@ trx_undo_report_row_operation( *roll_ptr = trx_undo_build_roll_ptr( op_type == TRX_UNDO_INSERT_OP, rseg->id, page_no, offset); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_SUCCESS); + err = DB_SUCCESS; + goto func_exit; } ut_ad(page_no == undo->last_page_no); /* We have to extend the undo log by one page */ + ut_ad(++loop_count < 2); mtr_start(&mtr); /* When we add a page to an undo log, this is analogous to @@ -1312,18 +1337,19 @@ trx_undo_report_row_operation( page_no = trx_undo_add_page(trx, undo, &mtr); mutex_exit(&(rseg->mutex)); + } while (UNIV_LIKELY(page_no != FIL_NULL)); - if (UNIV_UNLIKELY(page_no == FIL_NULL)) { - /* Did not succeed: out of space */ + /* Did not succeed: out of space */ + err = DB_OUT_OF_FILE_SPACE; - mutex_exit(&(trx->undo_mutex)); - mtr_commit(&mtr); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_OUT_OF_FILE_SPACE); - } +err_exit: + mutex_exit(&trx->undo_mutex); + mtr_commit(&mtr); +func_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); } + return(err); } /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/ diff --git a/storage/innodb_plugin/trx/trx0undo.c b/storage/innodb_plugin/trx/trx0undo.c index 7f03b68fb55..c36f55fbd9c 100644 --- a/storage/innodb_plugin/trx/trx0undo.c +++ b/storage/innodb_plugin/trx/trx0undo.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, 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 @@ -912,7 +912,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr); + TRUE, mtr, mtr); fil_space_release_free_extents(undo->space, n_reserved); @@ -998,29 +998,28 @@ trx_undo_free_page( } /********************************************************************//** -Frees an undo log page when there is also the memory object for the undo -log. */ -static +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN void -trx_undo_free_page_in_rollback( -/*===========================*/ - trx_t* trx __attribute__((unused)), /*!< in: transaction */ - trx_undo_t* undo, /*!< in: undo log memory copy */ - ulint page_no,/*!< in: page number to free: must not be the - header page */ - mtr_t* mtr) /*!< in: mtr which does not have a latch to any - undo log page; the caller must have reserved - the rollback segment mutex */ +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ { - ulint last_page_no; + ut_ad(mutex_own(&trx->undo_mutex)); + ut_ad(undo->hdr_page_no != undo->last_page_no); + ut_ad(undo->size > 0); - ut_ad(undo->hdr_page_no != page_no); - ut_ad(mutex_own(&(trx->undo_mutex))); + undo->last_page_no = trx_undo_free_page( + undo->rseg, FALSE, undo->space, + undo->hdr_page_no, undo->last_page_no, mtr); - last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space, - undo->hdr_page_no, page_no, mtr); - - undo->last_page_no = last_page_no; undo->size--; } @@ -1056,9 +1055,11 @@ Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ trx_undo_t* undo, /*!< in: undo log */ undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ @@ -1084,18 +1085,7 @@ trx_undo_truncate_end( rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no, undo->hdr_offset); - for (;;) { - if (rec == NULL) { - if (last_page_no == undo->hdr_page_no) { - - goto function_exit; - } - - trx_undo_free_page_in_rollback( - trx, undo, last_page_no, &mtr); - break; - } - + while (rec) { if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit) >= 0) { /* Truncate at least this record off, maybe @@ -1110,6 +1100,14 @@ trx_undo_truncate_end( undo->hdr_offset); } + if (last_page_no == undo->hdr_page_no) { + + goto function_exit; + } + + ut_ad(last_page_no == undo->last_page_no); + trx_undo_free_last_page(trx, undo, &mtr); + mtr_commit(&mtr); } From d7264adc8a20a5c0ce9f7bb714024ceb5bdb726b Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Mon, 29 Aug 2011 01:29:57 -0700 Subject: [PATCH 054/143] Fix Bug #12882177 - INSTRUMENTATION IN PFS_MUTEX_ENTER_NOWAIT_FUNC IS INCORRECT Use PSI_MUTEX_TRYLOCK instead of PSI_MUTEX_LOCK when acquire mutex with "no_wait" option Approved by Sunny Bains --- storage/innobase/include/sync0sync.ic | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index 2977f71154a..eb21f44c65e 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -272,11 +272,10 @@ pfs_mutex_enter_nowait_func( ulint ret; struct PSI_mutex_locker* locker = NULL; PSI_mutex_locker_state state; - int result = 0; if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) { locker = PSI_server->get_thread_mutex_locker( - &state, mutex->pfs_psi, PSI_MUTEX_LOCK); + &state, mutex->pfs_psi, PSI_MUTEX_TRYLOCK); if (locker) { PSI_server->start_mutex_wait(locker, file_name, line); } @@ -285,7 +284,7 @@ pfs_mutex_enter_nowait_func( ret = mutex_enter_nowait_func(mutex, file_name, line); if (locker) { - PSI_server->end_mutex_wait(locker, result); + PSI_server->end_mutex_wait(locker, ret); } return(ret); From f610c5658748ae97a5e2c1e1afbd229f2121a082 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 29 Aug 2011 11:24:36 +0200 Subject: [PATCH 055/143] BUG#12911710 - VALGRIND FAILURE IN ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC Converting the number zero to binary and back yielded the number zero, but with no digits, i.e. zero precision. This made the multiply algorithm go haywire in various ways. include/decimal.h: Document struct st_decimal_t mysql-test/r/type_newdecimal.result: New test case (valgrind warnings) mysql-test/t/type_newdecimal.test: New test case (valgrind warnings) sql/my_decimal.h: Remove the HAVE_purify enabled/disabled code. strings/decimal.c: Make a proper zero, with non-zero precision. --- include/decimal.h | 9 +++++++++ mysql-test/r/type_newdecimal.result | 11 +++++++++++ mysql-test/t/type_newdecimal.test | 14 ++++++++++++++ sql/my_decimal.h | 6 +----- strings/decimal.c | 9 ++++++++- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/decimal.h b/include/decimal.h index 530ed9e1757..c377bd4a400 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -21,6 +21,15 @@ typedef enum decimal_round_mode; typedef int32 decimal_digit_t; +/** + intg is the number of *decimal* digits (NOT number of decimal_digit_t's !) + before the point + frac is the number of decimal digits after the point + len is the length of buf (length of allocated space) in decimal_digit_t's, + not in bytes + sign false means positive, true means negative + buf is an array of decimal_digit_t's + */ typedef struct st_decimal_t { int intg, frac, len; my_bool sign; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c301a7dd629..0c6c1333e9b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1927,3 +1927,14 @@ f1 0.000000000000000000000000 DROP TABLE IF EXISTS t1; End of 5.1 tests +# +# BUG#12911710 - VALGRIND FAILURE IN +# ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC +# +CREATE TABLE t1(d1 DECIMAL(60,0) NOT NULL, +d2 DECIMAL(60,0) NOT NULL); +INSERT INTO t1 (d1, d2) VALUES(0.0, 0.0); +SELECT d1 * d2 FROM t1; +d1 * d2 +0 +DROP TABLE t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 31a8808da55..567d6c0b6a1 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1526,3 +1526,17 @@ DROP TABLE IF EXISTS t1; --echo End of 5.1 tests + +--echo # +--echo # BUG#12911710 - VALGRIND FAILURE IN +--echo # ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC +--echo # + +CREATE TABLE t1(d1 DECIMAL(60,0) NOT NULL, + d2 DECIMAL(60,0) NOT NULL); + +INSERT INTO t1 (d1, d2) VALUES(0.0, 0.0); +SELECT d1 * d2 FROM t1; + +DROP TABLE t1; + diff --git a/sql/my_decimal.h b/sql/my_decimal.h index c7a99e10233..21f485560da 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -101,12 +101,8 @@ public: { len= DECIMAL_BUFF_LENGTH; buf= buffer; -#if !defined (HAVE_purify) && !defined(DBUG_OFF) - /* Set buffer to 'random' value to find wrong buffer usage */ - for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) - buffer[i]= i; -#endif } + my_decimal() { init(); diff --git a/strings/decimal.c b/strings/decimal.c index 43957c7dc19..6c89657004c 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1423,11 +1423,18 @@ int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale) buf++; } my_afree(d_copy); + + /* + No digits? We have read the number zero, of unspecified precision. + Make it a proper zero, with non-zero precision. + */ + if (to->intg == 0 && to->frac == 0) + decimal_make_zero(to); return error; err: my_afree(d_copy); - decimal_make_zero(((decimal_t*) to)); + decimal_make_zero(to); return(E_DEC_BAD_NUM); } From 07770e7e8e43f482589b964fab0e74fcd1cba7c2 Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Mon, 29 Aug 2011 02:44:28 -0700 Subject: [PATCH 056/143] Fix Bug 12922077 - SEGV IN DICT_SET_CORRUPTED_INDEX_CACHE_ONLY(), DROP TABLE rb://752 approved by Sunny Bains --- storage/innobase/dict/dict0dict.c | 12 ++++++++++-- storage/innobase/dict/dict0load.c | 3 ++- storage/innobase/include/dict0dict.h | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index dfb733cb36c..2a2c7652817 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -5206,7 +5206,8 @@ UNIV_INTERN void dict_set_corrupted_index_cache_only( /*================================*/ - dict_index_t* index) /*!< in/out: index */ + dict_index_t* index, /*!< in/out: index */ + dict_table_t* table) /*!< in/out: table */ { ut_ad(index); ut_ad(mutex_own(&dict_sys->mutex)); @@ -5216,7 +5217,14 @@ dict_set_corrupted_index_cache_only( /* Mark the table as corrupted only if the clustered index is corrupted */ if (dict_index_is_clust(index)) { - index->table->corrupted = TRUE; + dict_table_t* corrupt_table; + + corrupt_table = table ? table : index->table; + ut_ad(!index->table || !table || index->table == table); + + if (corrupt_table) { + corrupt_table->corrupted = TRUE; + } } index->type |= DICT_CORRUPT; diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 60590aa6638..e13cc1b31f1 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -1497,7 +1497,8 @@ dict_load_indexes( dictionary cache for such metadata corruption, since we would always be able to set it when loading the dictionary cache */ - dict_set_corrupted_index_cache_only(index); + dict_set_corrupted_index_cache_only( + index, table); fprintf(stderr, "InnoDB: Index is corrupt but forcing" diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 93e9162dc87..57e51cbb6ba 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1298,7 +1298,8 @@ UNIV_INTERN void dict_set_corrupted_index_cache_only( /*================================*/ - dict_index_t* index); /*!< in/out: index */ + dict_index_t* index, /*!< in/out: index */ + dict_table_t* table); /*!< in/out: table */ /**********************************************************************//** Flags a table with specified space_id corrupted in the table dictionary From c6de8c8c05d020f16817fb0bfb05c9c3df475a76 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Tue, 30 Aug 2011 09:56:07 +0200 Subject: [PATCH 057/143] Bug#11765254 - 58200: ASSERTION FAILED: PARAM.SORT_LENGTH WHEN GROUPING BY FUNCTIONS.... (PART The bug was introduced in a patch for bug 49897. Problem: The assertion inserted by the original patch to guard against zero-lenght sort keys during merge phase triggers also when the whole set fits in memory. Fix: Move assert so that it does not trigger if the whole set is in memory. mysql-test/r/group_by.result: Add test for bug#11765254 mysql-test/t/group_by.test: Add test for bug#11765254 sql/filesort.cc: Move assertion --- mysql-test/r/group_by.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/group_by.test | 14 ++++++++++++++ sql/filesort.cc | 5 +++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 1dfb0f5860a..2c9f6116eed 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1891,4 +1891,36 @@ a AVG(t1.b) t11c t12c 1 4.0000 6 6 2 2.0000 7 7 DROP TABLE t1; +# +# Bug#11765254 (58200): Assertion failed: param.sort_length when grouping +# by functions +# +SET SQL_BIG_TABLES=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(0); +SELECT 1 FROM t1 GROUP BY IF(`a`,'',''); +1 +1 +SELECT 1 FROM t1 GROUP BY TRIM(LEADING RAND() FROM ''); +1 +1 +SELECT 1 FROM t1 GROUP BY SUBSTRING('',SLEEP(0),''); +1 +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' +Warning 1292 Truncated incorrect INTEGER value: '' +Warning 1292 Truncated incorrect INTEGER value: '' +SELECT 1 FROM t1 GROUP BY SUBSTRING(SYSDATE() FROM 'K' FOR 'jxW<'); +1 +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +DROP TABLE t1; +SET SQL_BIG_TABLES=0; # End of 5.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 1a4b9a3bab7..29ed26215bf 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1283,5 +1283,19 @@ FROM t1 GROUP BY a; DROP TABLE t1; +--echo # +--echo # Bug#11765254 (58200): Assertion failed: param.sort_length when grouping +--echo # by functions +--echo # + +SET SQL_BIG_TABLES=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(0); +SELECT 1 FROM t1 GROUP BY IF(`a`,'',''); +SELECT 1 FROM t1 GROUP BY TRIM(LEADING RAND() FROM ''); +SELECT 1 FROM t1 GROUP BY SUBSTRING('',SLEEP(0),''); +SELECT 1 FROM t1 GROUP BY SUBSTRING(SYSDATE() FROM 'K' FOR 'jxW<'); +DROP TABLE t1; +SET SQL_BIG_TABLES=0; --echo # End of 5.1 tests diff --git a/sql/filesort.cc b/sql/filesort.cc index 0ff354b334c..715528bcd52 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -144,8 +144,6 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, error= 1; bzero((char*) ¶m,sizeof(param)); param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset); - /* filesort cannot handle zero-length records. */ - DBUG_ASSERT(param.sort_length); param.ref_length= table->file->ref_length; param.addon_field= 0; param.addon_length= 0; @@ -257,6 +255,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } else { + /* filesort cannot handle zero-length records during merge. */ + DBUG_ASSERT(param.sort_length != 0); + if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer) { x_free(table_sort.buffpek); From 034db5cb82c4dbb71262b783afae293d67da4a05 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 30 Aug 2011 10:19:36 +0200 Subject: [PATCH 058/143] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Post-push fix: The functions write_keys() and find_all_keys() may have a slightly different function signature, depending on compiler/platform/flags. --- mysql-test/valgrind.supp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 3751a339a1a..e2fdc727da5 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -792,6 +792,9 @@ fun:row_drop_table_for_mysql } +# Note the wildcard in the (mangled) function signatures of +# write_keys() and find_all_keys(). +# They both return ha_rows, which is platform dependent. { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one Memcheck:Param @@ -800,8 +803,8 @@ fun:my_write fun:my_b_flush_io_cache fun:_my_b_write - fun:_ZL10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ - fun:_ZL13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ + fun:_Z*10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ + fun:_Z*13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy } From 38bc8cf3923bd17de7a09abcd3ba30dd7cb0bd0d Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 30 Aug 2011 12:54:00 +0200 Subject: [PATCH 059/143] Add the manual page for "mysql_plugin" to the server RPM. --- support-files/mysql.spec.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index d492e8fc6b7..0475f132b41 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -970,6 +970,7 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/mysqld_safe.1* %doc %attr(644, root, man) %{_mandir}/man1/mysqldumpslow.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_install_db.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysql_plugin.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_secure_installation.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_setpermission.1* %doc %attr(644, root, man) %{_mandir}/man1/mysql_upgrade.1* @@ -996,11 +997,11 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_bindir}/mysql_convert_table_format %attr(755, root, root) %{_bindir}/mysql_fix_extensions %attr(755, root, root) %{_bindir}/mysql_install_db +%attr(755, root, root) %{_bindir}/mysql_plugin %attr(755, root, root) %{_bindir}/mysql_secure_installation %attr(755, root, root) %{_bindir}/mysql_setpermission %attr(755, root, root) %{_bindir}/mysql_tzinfo_to_sql %attr(755, root, root) %{_bindir}/mysql_upgrade -%attr(755, root, root) %{_bindir}/mysql_plugin %attr(755, root, root) %{_bindir}/mysql_zap %attr(755, root, root) %{_bindir}/mysqlbug %attr(755, root, root) %{_bindir}/mysqld_multi @@ -1133,6 +1134,10 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Tue Aug 30 2011 Joerg Bruehe + +- Add the manual page for "mysql_plugin" to the server package. + * Fri Aug 19 2011 Joerg Bruehe - Null-upmerge the fix of bug#37165: This spec file is not affected. From 6e3cee780cfacd9f812fb30d6cb5766e750e11f2 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 31 Aug 2011 16:45:52 +0200 Subject: [PATCH 060/143] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Post-push fix: Enable filesort pattern two, perfschema.selects failed. --- mysql-test/valgrind.supp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index d85ce5e3f86..571712a4089 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -894,16 +894,17 @@ fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy } -## { -## Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two -## Memcheck:Param -## write(buf) -## obj:*/libpthread*.so -## fun:my_write -## fun:my_b_flush_io_cache -## fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache -## fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy -## } +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:inline_mysql_file_write + fun:my_b_flush_io_cache + fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache + fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy +} { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / three From 247ada63afcceaaea93e2565f06f62356ccb04ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 1 Sep 2011 21:48:04 +0300 Subject: [PATCH 061/143] Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE This fix was accidentally pushed to mysql-5.1 after the 5.1.59 clone-off in bzr revision id marko.makela@oracle.com-20110829081642-z0w992a0mrc62s6w with the fix of Bug#12704861 Corruption after a crash during BLOB update but not merged to mysql-5.5 and upwards. In the Barracuda formats, the clustered index record no longer contains a prefix of off-page columns. Because of this, the undo log must contain these prefixes, so that purge and multi-versioning will continue to work. However, this also means that an undo log record can become too big to fit in an undo log page. (It is a limitation of the undo log that undo records cannot span across multiple pages.) In case the checks for undo log size fail when CREATE TABLE or CREATE INDEX is executed, we need a fallback that blocks a modification operation when the undo log record would exceed the maximum size. trx_undo_free_last_page_func(): Renamed from trx_undo_free_page_in_rollback(). Define the trx_t parameter only in debug builds. trx_undo_free_last_page(): Wrapper for trx_undo_free_last_page_func(). Pass the trx_t parameter only in debug builds. trx_undo_truncate_end_func(): Renamed from trx_undo_truncate_end(). Define the trx_t parameter only in debug builds. Rewrite a for(;;) loop as a while loop for clarity. trx_undo_truncate_end(): Wrapper for from trx_undo_truncate_end_func(). Pass the trx_t parameter only in debug builds. trx_undo_erase_page_end(): Return TRUE if the page was non-empty to begin with. Refuse to erase empty pages. trx_undo_report_row_operation(): If the page for which the undo log was too big was empty, free the undo page and return DB_TOO_BIG_RECORD. rb:749 approved by Inaam Rana --- include/my_base.h | 3 +- mysql-test/suite/innodb/r/innodb-index.result | 9 +++ mysql-test/suite/innodb/t/innodb-index.test | 13 ++++ mysys/my_handler_errors.h | 3 +- sql/handler.cc | 3 + sql/share/errmsg-utf8.txt | 3 + storage/innobase/handler/ha_innodb.cc | 2 + storage/innobase/include/db0err.h | 3 +- storage/innobase/include/trx0undo.h | 46 +++++++++++-- storage/innobase/row/row0mysql.c | 1 + storage/innobase/trx/trx0rec.c | 69 +++++++++++++------ storage/innobase/trx/trx0undo.c | 66 +++++++++--------- storage/innobase/ut/ut0ut.c | 2 + 13 files changed, 158 insertions(+), 65 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index cc02b0080d9..d9f08a3c467 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -448,7 +448,8 @@ enum ha_base_keytype { #define HA_ERR_TOO_MANY_CONCURRENT_TRXS 177 /*Too many active concurrent transactions */ #define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */ #define HA_ERR_INDEX_CORRUPT 179 /* Index corrupted */ -#define HA_ERR_LAST 179 /* Copy of last error nr */ +#define HA_ERR_UNDO_REC_TOO_BIG 180 /* Undo log record too big */ +#define HA_ERR_LAST 180 /* Copy of last error nr */ /* Number of different errors */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index aa03c72022b..2e9ee652a76 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/r/innodb-index.result @@ -975,6 +975,15 @@ 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(767)), INDEX(b(767)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7751)); +COMMIT; +UPDATE bug12547647 SET c = REPEAT('b',16928); +ERROR HY000: Undo log record is too big. +DROP TABLE bug12547647; set global innodb_file_per_table=0; set global innodb_file_format=Antelope; set global innodb_file_format_max=Antelope; diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test index fad90e280fc..1df65afe94c 100644 --- a/mysql-test/suite/innodb/t/innodb-index.test +++ b/mysql-test/suite/innodb/t/innodb-index.test @@ -477,6 +477,19 @@ DELETE FROM t1; -- 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, +PRIMARY KEY (b(10), a), INDEX (c(767)), INDEX(b(767)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7751)); +COMMIT; +# The following used to cause infinite undo log allocation. +--error ER_UNDO_RECORD_TOO_BIG +UPDATE bug12547647 SET c = REPEAT('b',16928); +DROP TABLE bug12547647; + eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; eval set global innodb_file_format_max=$format; diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h index 428a58b0767..3533b633960 100644 --- a/mysys/my_handler_errors.h +++ b/mysys/my_handler_errors.h @@ -82,7 +82,8 @@ static const char *handler_error_messages[]= "Read page with wrong checksum", "Too many active concurrent transactions", "Index column length exceeds limit", - "Index corrupted" + "Index corrupted", + "Undo record too big" }; extern void my_handler_error_register(void); diff --git a/sql/handler.cc b/sql/handler.cc index db1eea6484b..6f7cf2c3456 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2869,6 +2869,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_INDEX_CORRUPT: textno= ER_INDEX_CORRUPT; break; + case HA_ERR_UNDO_REC_TOO_BIG: + textno= ER_UNDO_RECORD_TOO_BIG; + break; default: { /* The error was "unknown" to this function. diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 519d693f96d..58dea797dda 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6417,3 +6417,6 @@ ER_ERROR_IN_UNKNOWN_TRIGGER_BODY ER_INDEX_CORRUPT eng "Index %s is corrupted" + +ER_UNDO_RECORD_TOO_BIG + eng "Undo log record is too big." diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c4283d65a2a..7592b201ceb 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1045,6 +1045,8 @@ convert_error_code_to_mysql( return(HA_ERR_UNSUPPORTED); case DB_INDEX_CORRUPT: return(HA_ERR_INDEX_CORRUPT); + case DB_UNDO_RECORD_TOO_BIG: + return(HA_ERR_UNDO_REC_TOO_BIG); } } diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 415470b61b4..e0952f0709d 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, 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 @@ -111,6 +111,7 @@ enum db_err { DB_TOO_BIG_INDEX_COL, /* index column size exceeds maximum limit */ DB_INDEX_CORRUPT, /* we have corrupted index */ + DB_UNDO_RECORD_TOO_BIG, /* the undo log record is too big */ /* The following are partial failure codes */ DB_FAIL = 1000, diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index df16c939070..50aa6d0ac09 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, 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 @@ -204,17 +204,51 @@ trx_undo_add_page( mtr_t* mtr); /*!< in: mtr which does not have a latch to any undo log page; the caller must have reserved the rollback segment mutex */ +/********************************************************************//** +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN +void +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(trx,undo,mtr) +#else /* UNIV_DEBUG */ +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(undo,mtr) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ - trx_undo_t* undo, /*!< in: undo log */ - undo_no_t limit); /*!< in: all undo records with undo number +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log */ + undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(trx,undo,limit) +#else /* UNIV_DEBUG */ +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(undo,limit) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the start. This function is used during a purge operation. */ diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index d98d47a5da6..dd3aeef78ac 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -576,6 +576,7 @@ handle_new_error: case DB_DUPLICATE_KEY: case DB_FOREIGN_DUPLICATE_KEY: case DB_TOO_BIG_RECORD: + case DB_UNDO_RECORD_TOO_BIG: case DB_ROW_IS_REFERENCED: case DB_NO_REFERENCED_ROW: case DB_CANNOT_ADD_CONSTRAINT: diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index 5f83a9f5fd9..80c3d274e7c 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -669,7 +669,6 @@ trx_undo_page_report_modify( /* Save to the undo log the old values of the columns to be updated. */ if (update) { - if (trx_undo_left(undo_page, ptr) < 5) { return(0); @@ -1119,22 +1118,29 @@ trx_undo_rec_get_partial_row( #endif /* !UNIV_HOTBACKUP */ /***********************************************************************//** -Erases the unused undo log page end. */ -static -void +Erases the unused undo log page end. +@return TRUE if the page contained something, FALSE if it was empty */ +static __attribute__((nonnull, warn_unused_result)) +ibool trx_undo_erase_page_end( /*====================*/ - page_t* undo_page, /*!< in: undo page whose end to erase */ - mtr_t* mtr) /*!< in: mtr */ + page_t* undo_page, /*!< in/out: undo page whose end to erase */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint first_free; first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); + if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { + /* This was an empty page to begin with. + Do nothing here; the caller should free the page. */ + return(FALSE); + } memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); + return(TRUE); } /***********************************************************//** @@ -1156,7 +1162,11 @@ trx_undo_parse_erase_page_end( return(ptr); } - trx_undo_erase_page_end(page, mtr); + if (!trx_undo_erase_page_end(page, mtr)) { + /* The function trx_undo_erase_page_end() should not + have done anything to an empty page. */ + ut_ad(0); + } return(ptr); } @@ -1202,6 +1212,9 @@ trx_undo_report_row_operation( mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; +#ifdef UNIV_DEBUG + int loop_count = 0; +#endif /* UNIV_DEBUG */ rec_offs_init(offsets_); ut_a(dict_index_is_clust(index)); @@ -1264,7 +1277,7 @@ trx_undo_report_row_operation( mtr_start(&mtr); - for (;;) { + do { buf_block_t* undo_block; page_t* undo_page; ulint offset; @@ -1293,7 +1306,19 @@ trx_undo_report_row_operation( version the replicate page constructed using the log records stays identical to the original page */ - trx_undo_erase_page_end(undo_page, &mtr); + if (!trx_undo_erase_page_end(undo_page, &mtr)) { + /* The record did not fit on an empty + undo page. Discard the freshly allocated + page and return an error. */ + + mutex_enter(&rseg->mutex); + trx_undo_free_last_page(trx, undo, &mtr); + mutex_exit(&rseg->mutex); + + err = DB_UNDO_RECORD_TOO_BIG; + goto err_exit; + } + mtr_commit(&mtr); } else { /* Success */ @@ -1313,16 +1338,15 @@ trx_undo_report_row_operation( *roll_ptr = trx_undo_build_roll_ptr( op_type == TRX_UNDO_INSERT_OP, rseg->id, page_no, offset); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_SUCCESS); + err = DB_SUCCESS; + goto func_exit; } ut_ad(page_no == undo->last_page_no); /* We have to extend the undo log by one page */ + ut_ad(++loop_count < 2); mtr_start(&mtr); /* When we add a page to an undo log, this is analogous to @@ -1334,18 +1358,19 @@ trx_undo_report_row_operation( page_no = trx_undo_add_page(trx, undo, &mtr); mutex_exit(&(rseg->mutex)); + } while (UNIV_LIKELY(page_no != FIL_NULL)); - if (UNIV_UNLIKELY(page_no == FIL_NULL)) { - /* Did not succeed: out of space */ + /* Did not succeed: out of space */ + err = DB_OUT_OF_FILE_SPACE; - mutex_exit(&(trx->undo_mutex)); - mtr_commit(&mtr); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_OUT_OF_FILE_SPACE); - } +err_exit: + mutex_exit(&trx->undo_mutex); + mtr_commit(&mtr); +func_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); } + return(err); } /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/ diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 060a537c472..805fdcee242 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -1004,29 +1004,28 @@ trx_undo_free_page( } /********************************************************************//** -Frees an undo log page when there is also the memory object for the undo -log. */ -static +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN void -trx_undo_free_page_in_rollback( -/*===========================*/ - trx_t* trx __attribute__((unused)), /*!< in: transaction */ - trx_undo_t* undo, /*!< in: undo log memory copy */ - ulint page_no,/*!< in: page number to free: must not be the - header page */ - mtr_t* mtr) /*!< in: mtr which does not have a latch to any - undo log page; the caller must have reserved - the rollback segment mutex */ +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ { - ulint last_page_no; + ut_ad(mutex_own(&trx->undo_mutex)); + ut_ad(undo->hdr_page_no != undo->last_page_no); + ut_ad(undo->size > 0); - ut_ad(undo->hdr_page_no != page_no); - ut_ad(mutex_own(&(trx->undo_mutex))); + undo->last_page_no = trx_undo_free_page( + undo->rseg, FALSE, undo->space, + undo->hdr_page_no, undo->last_page_no, mtr); - last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space, - undo->hdr_page_no, page_no, mtr); - - undo->last_page_no = last_page_no; undo->size--; } @@ -1062,9 +1061,11 @@ Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ trx_undo_t* undo, /*!< in: undo log */ undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ @@ -1090,18 +1091,7 @@ trx_undo_truncate_end( rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no, undo->hdr_offset); - for (;;) { - if (rec == NULL) { - if (last_page_no == undo->hdr_page_no) { - - goto function_exit; - } - - trx_undo_free_page_in_rollback( - trx, undo, last_page_no, &mtr); - break; - } - + while (rec) { if (trx_undo_rec_get_undo_no(rec) >= limit) { /* Truncate at least this record off, maybe more */ @@ -1115,6 +1105,14 @@ trx_undo_truncate_end( undo->hdr_offset); } + if (last_page_no == undo->hdr_page_no) { + + goto function_exit; + } + + ut_ad(last_page_no == undo->last_page_no); + trx_undo_free_last_page(trx, undo, &mtr); + mtr_commit(&mtr); } diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index bd009f1fd32..f6dfb3ba0b3 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -714,6 +714,8 @@ ut_strerr( return("No index on referenced keys in referenced table"); case DB_INDEX_CORRUPT: return("Index corrupted"); + case DB_UNDO_RECORD_TOO_BIG: + return("Undo record too big"); case DB_END_OF_INDEX: return("End of index"); /* do not add default: in order to produce a warning if new code From a3ff4f7c9399f5973978a0c4c3b442c5c115c2f1 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 2 Sep 2011 16:52:04 +0530 Subject: [PATCH 062/143] BUG#11878394 - MYSQLD_SAFE TEST FOR ALREADY RUNNING PROCESS FAILS, CAUSING CLOBBERED SOCKET A check for running mysqld instances was failing in mysqld_safe because of an incorrect shell command generated by cmake. The problem is that cmake retains the '\' of escaped double-quote, so the generated mysqld_safe script's command contained \" in the shell command, and hence the failure. Fixed the command in scripts\CMakeLists.txt. scripts/CMakeLists.txt: BUG#1878394 - MYSQLD_SAFE TEST FOR ALREADY RUNNING PROCESS FAILS, CAUSING CLOBBERED SOCKET Removed the escaped quotes and grep for 'grep process' from the shell commands. --- scripts/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 56b7f779bb0..2efb348fcd5 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -104,11 +104,11 @@ IF(UNIX) # FIND_PROC and CHECK_PID are used by mysqld_safe IF(CMAKE_SYSTEM_NAME MATCHES "Linux") SET (FIND_PROC - "ps wwwp $PID | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" > /dev/null") + "ps wwwp $PID | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null") ENDIF() IF(NOT FIND_PROC AND CMAKE_SYSTEM_NAME MATCHES "SunOS") SET (FIND_PROC - "ps -p $PID | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" > /dev/null") + "ps -p $PID | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null") ENDIF() IF(NOT FIND_PROC) @@ -116,7 +116,7 @@ IF(NOT FIND_PROC) EXECUTE_PROCESS(COMMAND ps -uaxww OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) IF(result MATCHES 0) SET( FIND_PROC - "ps -uaxww | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" | grep \" $PID \" > /dev/null") + "ps -uaxww | grep -v mysqld_safe | grep -- $MYSQLD | grep $PID > /dev/null") ENDIF() ENDIF() @@ -124,7 +124,7 @@ IF(NOT FIND_PROC) # SysV style EXECUTE_PROCESS(COMMAND ps -ef OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE result) IF(result MATCHES 0) - SET( FIND_PROC "ps -ef | grep -v \" grep\" | grep -v mysqld_safe | grep -- \"$MYSQLD\" | grep \" $PID \" > /dev/null") + SET( FIND_PROC "ps -ef | grep -v mysqld_safe | grep -- $MYSQLD | grep $PID > /dev/null") ENDIF() ENDIF() From 52d9e13ffcacee74e42bc436877f5f4eb1999e66 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 5 Sep 2011 14:38:20 +0200 Subject: [PATCH 063/143] Bug #11750417 40942: UNABLE TO INSTALL FEDERATED PLUGIN Link plugin with a copy of string.o Copied test from 5.5 but this was dysfunctional, made it work Also tested on Windows --- mysql-test/include/have_federated_plugin.inc | 5 +++ mysql-test/mysql-test-run.pl | 18 ++++++++++ .../federated/federated_plugin-master.opt | 2 ++ .../suite/federated/federated_plugin.result | 19 +++++++++++ .../suite/federated/federated_plugin.test | 34 +++++++++++++++++++ storage/federated/Makefile.am | 4 +-- 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/have_federated_plugin.inc create mode 100644 mysql-test/suite/federated/federated_plugin-master.opt create mode 100644 mysql-test/suite/federated/federated_plugin.result create mode 100644 mysql-test/suite/federated/federated_plugin.test diff --git a/mysql-test/include/have_federated_plugin.inc b/mysql-test/include/have_federated_plugin.inc new file mode 100644 index 00000000000..5c7549de53f --- /dev/null +++ b/mysql-test/include/have_federated_plugin.inc @@ -0,0 +1,5 @@ +if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%federated%'`) +{ + --skip federated plugin not available +} + diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1c7efccc69d..7661714eb03 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1979,6 +1979,24 @@ sub environment_setup { $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename; } + # -------------------------------------------------------------------------- + # Add the path where mysqld will find ha_federated.so + # -------------------------------------------------------------------------- + my $fedplug_filename; + if (IS_WINDOWS) { + $fedplug_filename = "ha_federated.dll"; + } else { + $fedplug_filename = "ha_federated.so"; + } + my $lib_fed_plugin= + mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), + "$basedir/storage/federated/.libs/".$fedplug_filename, + "$basedir/lib/mysql/plugin/".$fedplug_filename); + + $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; + $ENV{'FEDERATED_PLUGIN_DIR'}= + ($lib_fed_plugin ? dirname($lib_fed_plugin) : ""); + # ---------------------------------------------------- # Add the path where mysqld will find mypluglib.so # ---------------------------------------------------- diff --git a/mysql-test/suite/federated/federated_plugin-master.opt b/mysql-test/suite/federated/federated_plugin-master.opt new file mode 100644 index 00000000000..027a6d949c0 --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin-master.opt @@ -0,0 +1,2 @@ +--plugin_dir=$FEDERATED_PLUGIN_DIR +--loose-federated=ON diff --git a/mysql-test/suite/federated/federated_plugin.result b/mysql-test/suite/federated/federated_plugin.result new file mode 100644 index 00000000000..b49a977d9df --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin.result @@ -0,0 +1,19 @@ +CREATE TABLE t2(a int); +CREATE TABLE t1(a int) ENGINE=FEDERATED +CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +Warnings: +Warning 1286 Unknown table engine 'FEDERATED' +Warning 1266 Using storage engine MyISAM for table 't1' +DROP TABLE t1; +INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; +INSTALL PLUGIN FEDERATED SONAME 'FEDERATED_PLUGIN'; +ERROR HY000: Function 'FEDERATED' already exists +UNINSTALL PLUGIN federated; +INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; +CREATE TABLE t1(a int) ENGINE=FEDERATED +CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; +UNINSTALL PLUGIN federated; +UNINSTALL PLUGIN federated; +ERROR 42000: PLUGIN federated does not exist +DROP TABLE t2; diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test new file mode 100644 index 00000000000..6e5152df17c --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin.test @@ -0,0 +1,34 @@ +--source include/have_federated_plugin.inc + +connect (master,localhost,root,,test,$MASTER_MYPORT,); +connect (slave,localhost,root,,test,$SLAVE_MYPORT,); + +connection master; +CREATE TABLE t2(a int); + +connection slave; +CREATE TABLE t1(a int) ENGINE=FEDERATED + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; + +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +--error ER_UDF_EXISTS +eval INSTALL PLUGIN FEDERATED SONAME '$FEDERATED_PLUGIN'; + +UNINSTALL PLUGIN federated; + +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; + +CREATE TABLE t1(a int) ENGINE=FEDERATED + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; + +UNINSTALL PLUGIN federated; +--error ER_SP_DOES_NOT_EXIST +UNINSTALL PLUGIN federated; + +connection master; +DROP TABLE t2; diff --git a/storage/federated/Makefile.am b/storage/federated/Makefile.am index e0dae69539e..9b4e74af0a7 100644 --- a/storage/federated/Makefile.am +++ b/storage/federated/Makefile.am @@ -37,14 +37,14 @@ pkgplugin_LTLIBRARIES = @plugin_federated_shared_target@ ha_federated_la_LDFLAGS = -module -rpath $(pkgplugindir) ha_federated_la_CXXFLAGS= $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN ha_federated_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -ha_federated_la_SOURCES = ha_federated.cc +ha_federated_la_SOURCES = ha_federated.cc $(top_srcdir)/mysys/string.c EXTRA_LIBRARIES = libfederated.a noinst_LIBRARIES = @plugin_federated_static_target@ libfederated_a_CXXFLAGS = $(AM_CXXFLAGS) libfederated_a_CFLAGS = $(AM_CFLAGS) -libfederated_a_SOURCES= ha_federated.cc +libfederated_a_SOURCES= ha_federated.cc $(top_srcdir)/mysys/string.c EXTRA_DIST = CMakeLists.txt plug.in From 0c5106fc65b5cc3bcdcbd915775639335c413fd0 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 5 Sep 2011 16:04:33 +0200 Subject: [PATCH 064/143] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Post-push fix: Replace fun:inline_mysql_file_write with '...' since it may be optimized away. --- mysql-test/valgrind.supp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 571712a4089..0ea50c92985 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -880,13 +880,16 @@ # Note the wildcard in the (mangled) function signatures of # write_keys() and find_all_keys(). # They both return ha_rows, which is platform dependent. +# +# The '...' wildcards are for 'fun:inline_mysql_file_write' which *may* +# be inlined. { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one Memcheck:Param write(buf) obj:*/libpthread*.so fun:my_write - fun:inline_mysql_file_write + ... fun:my_b_flush_io_cache fun:_my_b_write fun:_Z*10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ @@ -900,7 +903,7 @@ write(buf) obj:*/libpthread*.so fun:my_write - fun:inline_mysql_file_write + ... fun:my_b_flush_io_cache fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy @@ -912,7 +915,7 @@ write(buf) obj:*/libpthread*.so fun:my_write - fun:inline_mysql_file_write + ... fun:my_b_flush_io_cache fun:_Z8filesortP3THDP5TABLEP13st_sort_fieldjP10SQL_SELECTybPy } From 2f49da3fdc4b4dc727794d346d0de1bc2f6d5244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Sep 2011 10:04:21 +0300 Subject: [PATCH 065/143] Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE - take 2 The original fix was accidentally pushed to mysql-5.1 after the 5.1.59 clone-off in bzr revision id marko.makela@oracle.com-20110829081642-z0w992a0mrc62s6w with thne fix of Bug#12704861 Corruption after a crash during BLOB update. It was pushed separately to mysql-5.5 in bzr revision id marko.makela@oracle.com-20110901184804-2901f6qmuro3jas8. trx_undo_report_row_operation(): If the page for which the undo log was too big was empty, commit and start the mini-transaction before acquiring the rollback segment mutex and freeing the undo page. This is necessary, because the mini-transaction may be holding lower-order latches in the levels SYNC_FSP and SYNC_FSP_PAGE. trx_undo_erase_page_end(): Erase also empty pages, because trx_undo_report_row_operation() needs to commit the mini-transaction before freeing the empty page. rb:756 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 10 +++++----- storage/innodb_plugin/trx/trx0rec.c | 27 +++++++++++++++------------ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 96b6a47085a..328cafff58f 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-06 The InnoDB Team + + * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: + Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE + 2011-08-29 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, @@ -7,11 +12,6 @@ Fix Bug#12704861 Corruption after a crash during BLOB update and other regressions from the fix of Bug#12612184 -2011-08-23 The InnoDB Team - - * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: - Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE - 2011-08-15 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index a729a39d0cc..2db98e029df 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1099,7 +1099,7 @@ trx_undo_rec_get_partial_row( /***********************************************************************//** Erases the unused undo log page end. @return TRUE if the page contained something, FALSE if it was empty */ -static __attribute__((nonnull, warn_unused_result)) +static __attribute__((nonnull)) ibool trx_undo_erase_page_end( /*====================*/ @@ -1110,16 +1110,11 @@ trx_undo_erase_page_end( first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); - if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { - /* This was an empty page to begin with. - Do nothing here; the caller should free the page. */ - return(FALSE); - } memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); - return(TRUE); + return(first_free != TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); } /***********************************************************//** @@ -1141,11 +1136,7 @@ trx_undo_parse_erase_page_end( return(ptr); } - if (!trx_undo_erase_page_end(page, mtr)) { - /* The function trx_undo_erase_page_end() should not - have done anything to an empty page. */ - ut_ad(0); - } + trx_undo_erase_page_end(page, mtr); return(ptr); } @@ -1290,6 +1281,18 @@ trx_undo_report_row_operation( undo page. Discard the freshly allocated page and return an error. */ + /* When we remove a page from an undo + log, this is analogous to a + pessimistic insert in a B-tree, and we + must reserve the counterpart of the + tree latch, which is the rseg + mutex. We must commit the mini-transaction + first, because it may be holding lower-level + latches, such as SYNC_FSP and SYNC_FSP_PAGE. */ + + mtr_commit(&mtr); + mtr_start(&mtr); + mutex_enter(&rseg->mutex); trx_undo_free_last_page(trx, undo, &mtr); mutex_exit(&rseg->mutex); From 7f48c174f0b589f307c54f2bab28a465ffc92468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Sep 2011 10:08:52 +0300 Subject: [PATCH 066/143] Bug #12950803 62294: BUF_BUDDY_RELOCATE CALLS GETTIMEOFDAY ... buf_buddy_relocate(): The ut_time_us() function is needed for statistics, calculating the total time spent on relocating blocks. Until now, we invoked ut_time_us() every time buf_buddy_relocate() was called. Fix: Only call ut_time_us() when the block can be relocated. After this fix, the reported relocated_usec will no longer include the time for the page_hash lookup and for acquiring the block mutex. Approved by Sunny Bains on IM --- storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/buf/buf0buddy.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 328cafff58f..a29aaf2077e 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2011-09-06 The InnoDB Team + + * buf/buf0buddy.c: + Fix Bug#12950803 62294: BUF_BUDDY_RELOCATE CALLS GETTIMEOFDAY + WHILE HOLDING BUFFER POOL MUTEX + 2011-09-06 The InnoDB Team * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: diff --git a/storage/innodb_plugin/buf/buf0buddy.c b/storage/innodb_plugin/buf/buf0buddy.c index de571743361..efc4fd46e90 100644 --- a/storage/innodb_plugin/buf/buf0buddy.c +++ b/storage/innodb_plugin/buf/buf0buddy.c @@ -327,7 +327,6 @@ buf_buddy_relocate( { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; - ullint usec = ut_time_us(NULL); mutex_t* mutex; ulint space; ulint page_no; @@ -394,6 +393,7 @@ buf_buddy_relocate( if (buf_page_can_relocate(bpage)) { /* Relocate the compressed page. */ + ullint usec = ut_time_us(NULL); ut_a(bpage->zip.data == src); memcpy(dst, src, size); bpage->zip.data = dst; From 006a6dc3ccfde6d7b1553c3d620db79233821098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Sep 2011 10:18:03 +0300 Subject: [PATCH 067/143] Bug#11766305 - 59392: Remove thr0loc.c and ibuf_inside() - cleanup Remove the unused debug constants for the latching order level SYNC_THR_LOCAL. --- storage/innobase/include/sync0sync.h | 1 - storage/innobase/sync/sync0sync.c | 1 - 2 files changed, 2 deletions(-) diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 9c0d5e3c302..f6b8897522f 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -684,7 +684,6 @@ or row lock! */ #define SYNC_BUF_FLUSH_LIST 145 /* Buffer flush list mutex */ #define SYNC_DOUBLEWRITE 140 #define SYNC_ANY_LATCH 135 -#define SYNC_THR_LOCAL 133 #define SYNC_MEM_HASH 131 #define SYNC_MEM_POOL 130 diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 5de8dfe0a6f..8e082be33f7 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1214,7 +1214,6 @@ sync_thread_add_level( case SYNC_WORK_QUEUE: case SYNC_LOG: case SYNC_LOG_FLUSH_ORDER: - case SYNC_THR_LOCAL: case SYNC_ANY_LATCH: case SYNC_FILE_FORMAT_TAG: case SYNC_DOUBLEWRITE: From 079d3cc6a6d19c2baf98c703ba28af47b45b0f4f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:06:09 +0530 Subject: [PATCH 068/143] Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Added help message for the missing options (--no-defaults, --defaults-file and --defaults-extra-file). --- scripts/mysql_install_db.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index b9b31a2d78e..6fe9712b23a 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -46,10 +46,16 @@ Usage: $0 [OPTIONS] --cross-bootstrap For internal use. Used when building the MySQL system tables on a different host than the target. --datadir=path The path to the MySQL data directory. + --defaults-extra-file=name + Read this file after the global files are read. + + --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally use hostnames will use IP addresses. + --help Display this help and exit. --ldata=path The path to the MySQL data directory. Same as --datadir. + --no-defaults Don't read default options from any option file. --rpm For internal use. This option is used by RPM files during the MySQL installation process. --skip-name-resolve Use IP addresses rather than hostnames when creating From d24953af5cbef54222c14325d75a34f598f1e25f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:25:28 +0530 Subject: [PATCH 069/143] Removing a stray line, went into the last push. --- scripts/mysql_install_db.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 6fe9712b23a..9782a37c462 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -48,7 +48,6 @@ Usage: $0 [OPTIONS] --datadir=path The path to the MySQL data directory. --defaults-extra-file=name Read this file after the global files are read. - --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally From a667fe030b2b03370b2f0eb39e2fa2ed8f13ddf5 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:50:04 +0530 Subject: [PATCH 070/143] Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Updating help message in scripts/mysql_install_db.pl.in file. scripts/mysql_install_db.pl.in: Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Updating help message. --- scripts/mysql_install_db.pl.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mysql_install_db.pl.in b/scripts/mysql_install_db.pl.in index 18bd713c041..7bc1e97e7be 100644 --- a/scripts/mysql_install_db.pl.in +++ b/scripts/mysql_install_db.pl.in @@ -61,10 +61,15 @@ Usage: $0 [OPTIONS] --cross-bootstrap For internal use. Used when building the MySQL system tables on a different host than the target. --datadir=path The path to the MySQL data directory. + --defaults-extra-file=name + Read this file after the global files are read. + --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally use hostnames will use IP addresses. + --help Display this help and exit. --ldata=path The path to the MySQL data directory. Same as --datadir. + --no-defaults Don't read default options from any option file. --rpm For internal use. This option is used by RPM files during the MySQL installation process. --skip-name-resolve Use IP addresses rather than hostnames when creating From b5c334efb232b8c7c10cd08a4725d4a0df8782ba Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 7 Sep 2011 13:50:51 +0200 Subject: [PATCH 071/143] WL#5973: Support marking plugins as not possible to install or uninstall dynamically This patch does the following: - Step the plugin interface version. - A flag field to the st_mysql_plugin structure that is used by plugins to provide basic information about the plugin. - Two new flags to mark that a plugin cannot be loaded or unloaded dynamically (from a running server) but has to be installed or uninstalled offline. - Two new error messages for reporting error when trying to install or uninstall a plugin marked as not instal- lable or not uninstallable. - Update all plugins to initialize the new flags field to 0 explicitly. This is a missing commit message for revision: mats.kindahl@oracle.com-20110815181211-4l94m162xs1mtrei From 7822b78d8551b1b8c8eb16de7b4f4ba3975206e5 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 7 Sep 2011 17:00:51 +0300 Subject: [PATCH 072/143] Bug #12944747: MYSQL PROXY CAN'T DISTINGUISH WIN-AUTH DATA FROM OK PACKET There's no reliable way (without knowing the protocol variants that each plugin pair implements) to find out when does the authentication exchange end. The server is changed to send all the extra authentication packets that server plugins need to send prefixed with the \x1 command. --- sql/sql_acl.cc | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 87beb71cca5..3f236dd672f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8820,24 +8820,18 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, /** - Make sure that when sending plugin supplued data to the client they + Make sure that when sending plugin supplied data to the client they are not considered a special out-of-band command, like e.g. - \255 (error) or \254 (change user request packet). - To avoid this we send plugin data packets starting with one of these - 2 bytes "wrapped" in a command \1. - For the above reason we have to wrap plugin data packets starting with - \1 as well. + \255 (error) or \254 (change user request packet) or \0 (OK). + To avoid this the server will send all plugin data packets "wrapped" + in a command \1. + Note that the client will continue sending its replies unrwapped. */ -#define IS_OUT_OF_BAND_PACKET(packet,packet_len) \ - ((packet_len) > 0 && \ - (*(packet) == 1 || *(packet) == 255 || *(packet) == 254)) - static inline int wrap_plguin_data_into_proper_command(NET *net, const uchar *packet, int packet_len) { - DBUG_ASSERT(IS_OUT_OF_BAND_PACKET(packet, packet_len)); return net_write_command(net, 1, (uchar *) "", 0, packet, packet_len); } @@ -8874,13 +8868,8 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param, res= send_server_handshake_packet(mpvio, (char*) packet, packet_len); else if (mpvio->status == MPVIO_EXT::RESTART) res= send_plugin_request_packet(mpvio, packet, packet_len); - else if (IS_OUT_OF_BAND_PACKET(packet, packet_len)) - res= wrap_plguin_data_into_proper_command(mpvio->net, packet, packet_len); else - { - res= my_net_write(mpvio->net, packet, packet_len) || - net_flush(mpvio->net); - } + res= wrap_plguin_data_into_proper_command(mpvio->net, packet, packet_len); mpvio->packets_written++; DBUG_RETURN(res); } From b7478b966a0558655b57c703b5768d3e96b01d36 Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Wed, 7 Sep 2011 10:46:20 -0400 Subject: [PATCH 073/143] BUG#12929631 : Execute crashes with --verbose output (Windows) This patch corrects an unsafe string concatenation in the Windows specific code for building the bootstrap command to enable or disable the plugin. --- client/mysql_plugin.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 6679fa9ca6f..267ede5447c 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1157,10 +1157,11 @@ static int bootstrap_server(char *server_path, char *bootstrap_file) #ifdef __WIN__ char *format_str= 0; - char *verbose_str= ""; + const char *verbose_str= NULL; + if (opt_verbose) - strcat(verbose_str, "--console"); + verbose_str= "--console"; if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || has_spaces(bootstrap_file)) format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; From 10e7b94834e09411367482e07926fd6907e69067 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Wed, 7 Sep 2011 17:58:10 +0300 Subject: [PATCH 074/143] Use cursors for seeking records in SYS_FOREIGN and SYS_INDEXES from DROP_TABLE_PROC(). With this change I observe a speedup from 6.2s to 0.1s when executing DROP_TABLE_PROC() during DROP TABLE with 512 foreign keys, like what is being done in innodb_bug56143.test This fixes "Bug#11765460 DROP TABLE USES INEFFICIENT METHODS TO REMOVE FKS/INDEXES FROM INNODB SYS TABLES" Reviewed by: Marko --- storage/innodb_plugin/row/row0mysql.c | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index c4911400cee..4e6a49cf8b0 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3221,6 +3221,19 @@ check_next_foreign: "index_id CHAR;\n" "foreign_id CHAR;\n" "found INT;\n" + + "DECLARE CURSOR cur_fk IS\n" + "SELECT ID FROM SYS_FOREIGN\n" + "WHERE FOR_NAME = :table_name\n" + "AND TO_BINARY(FOR_NAME)\n" + " = TO_BINARY(:table_name)\n" + "LOCK IN SHARE MODE;\n" + + "DECLARE CURSOR cur_idx IS\n" + "SELECT ID FROM SYS_INDEXES\n" + "WHERE TABLE_ID = table_id\n" + "LOCK IN SHARE MODE;\n" + "BEGIN\n" "SELECT ID INTO table_id\n" "FROM SYS_TABLES\n" @@ -3243,13 +3256,9 @@ check_next_foreign: "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n" " found := 0;\n" "END IF;\n" + "OPEN cur_fk;\n" "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = :table_name\n" - " AND TO_BINARY(FOR_NAME)\n" - " = TO_BINARY(:table_name)\n" - " LOCK IN SHARE MODE;\n" + " FETCH cur_fk INTO foreign_id;\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE\n" @@ -3259,12 +3268,11 @@ check_next_foreign: " WHERE ID = foreign_id;\n" " END IF;\n" "END LOOP;\n" + "CLOSE cur_fk;\n" "found := 1;\n" + "OPEN cur_idx;\n" "WHILE found = 1 LOOP\n" - " SELECT ID INTO index_id\n" - " FROM SYS_INDEXES\n" - " WHERE TABLE_ID = table_id\n" - " LOCK IN SHARE MODE;\n" + " FETCH cur_idx INTO index_id;\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE\n" @@ -3275,6 +3283,7 @@ check_next_foreign: " AND TABLE_ID = table_id;\n" " END IF;\n" "END LOOP;\n" + "CLOSE cur_idx;\n" "DELETE FROM SYS_COLUMNS\n" "WHERE TABLE_ID = table_id;\n" "DELETE FROM SYS_TABLES\n" From 0750d88c150581b386ad2cee9ac83b87404d8d0f Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Wed, 7 Sep 2011 13:09:27 -0400 Subject: [PATCH 075/143] BUG#12929345 : Execution aborts without any messages (Windows only) This patch corrects an unsafe string concatenation for a Windows-specific code segment. The symptoms were, under certain conditions like specifying the location of my-print-defaults and the basedir, and run on a release build, the client would exit without printing any messages. --- client/mysql_plugin.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 267ede5447c..ec3dc64f0d8 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -846,12 +846,19 @@ static int process_options(int argc, char *argv[], char *operation) { i= (int)strlength(opt_basedir); if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) + { + char buff[FN_REFLEN]; + + strncpy(buff, opt_basedir, sizeof(buff) - 1); #ifdef __WIN__ - if (opt_basedir[i-1] != '/') - strcat(opt_basedir, "//"); + strncat(buff, "/", sizeof(buff) - 1); #else - strcat(opt_basedir, FN_DIRSEP); + strncat(buff, FN_DIRSEP, sizeof(buff) - 1); #endif + buff[sizeof(buff) - 1]= 0; + my_delete(opt_basedir, MYF(0)); + opt_basedir= my_strdup(buff, MYF(MY_FAE)); + } } /* From cee822ca793a0473aef2a2d00d25ed2fdb17f2ad Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 7 Sep 2011 20:02:35 +0200 Subject: [PATCH 076/143] Bug#12873214 WINDOWS AUTHENTICATION PLUGIN PRODUCES EXCESSIVE RECORDS IN SERVER ERROR LOG Changed semantics of AUTHENTICATION_WIN_LOG environment variable recognized by client library to accept the following values which are levels of logging done during Windows authentication handshake: 0 - no logging 1 - log only error messages 2 - additionally log warnings 3 - additionally log info notes 4 - also log debug messages Setting it to 'on', 'yes' or 'true' will request log level 2 and setting it to 'debug' or 'dbug' will request log level 4. --- libmysql/authentication_win/common.cc | 18 +++++++ libmysql/authentication_win/common.h | 14 +++--- .../authentication_win/handshake_client.cc | 12 ++--- libmysql/authentication_win/log_client.cc | 50 +++++++++++-------- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/libmysql/authentication_win/common.cc b/libmysql/authentication_win/common.cc index 1d1f2938969..9544e7734f5 100644 --- a/libmysql/authentication_win/common.cc +++ b/libmysql/authentication_win/common.cc @@ -22,6 +22,24 @@ template <> void error_log_print(const char *fmt, ...); template <> void error_log_print(const char *fmt, ...); template <> void error_log_print(const char *fmt, ...); +/** + Option indicating desired level of logging. Values: + + 0 - no logging + 1 - log only error messages + 2 - additionally log warnings + 3 - additionally log info notes + 4 - also log debug messages + + Value of this option should be taken into account in the + implementation of error_log_vprint() function (see + log_client.cc). + + Note: No error or debug messages are logged in production code + (see logging macros in common.h). +*/ +int opt_auth_win_log_level= 2; + /** Connection class **************************************************/ diff --git a/libmysql/authentication_win/common.h b/libmysql/authentication_win/common.h index ff0f7153664..7f7aa1d2dff 100644 --- a/libmysql/authentication_win/common.h +++ b/libmysql/authentication_win/common.h @@ -41,13 +41,15 @@ struct error_log_level typedef enum {INFO, WARNING, ERROR} type; }; +extern "C" int opt_auth_win_log_level; +unsigned int get_log_level(void); +void set_log_level(unsigned int); + /* If DEBUG_ERROR_LOG is defined then error logging happens only in debug-copiled code. Otherwise ERROR_LOG() expands to - error_log_print() even in production code. Note that in client - plugin, error_log_print() will print nothing if opt_auth_win_clinet_log - is 0. + error_log_print() even in production code. Note: Macro ERROR_LOG() can use printf-like format string like this: @@ -57,8 +59,6 @@ struct error_log_level to fprintf() (see error_log_vprint() function). */ -extern "C" int opt_auth_win_client_log; - #if defined(DEBUG_ERROR_LOG) && defined(DBUG_OFF) #define ERROR_LOG(Level, Msg) do {} while (0) #else @@ -67,7 +67,7 @@ extern "C" int opt_auth_win_client_log; void error_log_vprint(error_log_level::type level, - const char *fmt, va_list args); + const char *fmt, va_list args); template void error_log_print(const char *fmt, ...) @@ -96,7 +96,7 @@ const char* get_last_error_message(Error_message_buf); #define DBUG_PRINT_DO(Keyword, Msg) \ do { \ - if (2 > opt_auth_win_client_log) break; \ + if (4 > get_log_level()) break; \ fprintf(stderr, "winauth: %s: ", Keyword); \ debug_msg Msg; \ } while (0) diff --git a/libmysql/authentication_win/handshake_client.cc b/libmysql/authentication_win/handshake_client.cc index 7e89fc92ae7..565726651cb 100644 --- a/libmysql/authentication_win/handshake_client.cc +++ b/libmysql/authentication_win/handshake_client.cc @@ -323,13 +323,13 @@ int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) int opt_val= opt ? atoi(opt) : 0; if (opt && !opt_val) { - if (!strncasecmp("on", opt, 2)) opt_val= 1; - if (!strncasecmp("yes", opt, 3)) opt_val= 1; - if (!strncasecmp("true", opt, 4)) opt_val= 1; - if (!strncasecmp("debug", opt, 5)) opt_val= 2; - if (!strncasecmp("dbug", opt, 4)) opt_val= 2; + if (!strncasecmp("on", opt, 2)) opt_val= 2; + if (!strncasecmp("yes", opt, 3)) opt_val= 2; + if (!strncasecmp("true", opt, 4)) opt_val= 2; + if (!strncasecmp("debug", opt, 5)) opt_val= 4; + if (!strncasecmp("dbug", opt, 4)) opt_val= 4; } - opt_auth_win_client_log= opt_val; + set_log_level(opt_val); } ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user)); diff --git a/libmysql/authentication_win/log_client.cc b/libmysql/authentication_win/log_client.cc index df4ce4f9c2a..8a49c4220bb 100644 --- a/libmysql/authentication_win/log_client.cc +++ b/libmysql/authentication_win/log_client.cc @@ -16,36 +16,32 @@ #include #include "common.h" -/** - This option is set in win_auth_handshake_client() function - in handshake_client.cc. - - Values: - 0 - no logging - 1 - log error/warning/info messages - 2 - also log debug messages - - Note: No error or debug messages are logged in production code - (see logging macros in common.h). -*/ -int opt_auth_win_client_log= 0; - // Client-side logging function void error_log_vprint(error_log_level::type level, const char *fmt, va_list args) { - if (0 == opt_auth_win_client_log) - return; - const char *level_string= ""; + int log_level= get_log_level(); switch (level) { - case error_log_level::INFO: level_string= "Note"; break; - case error_log_level::WARNING: level_string= "Warning"; break; - case error_log_level::ERROR: level_string= "ERROR"; break; + case error_log_level::INFO: + if (3 > log_level) + return; + level_string= "Note"; + break; + case error_log_level::WARNING: + if (2 > log_level) + return; + level_string= "Warning"; + break; + case error_log_level::ERROR: + if (1 > log_level) + return; + level_string= "ERROR"; + break; } fprintf(stderr, "Windows Authentication Plugin %s: ", level_string); @@ -53,3 +49,17 @@ void error_log_vprint(error_log_level::type level, fputc('\n', stderr); fflush(stderr); } + + +// Trivial implementation of log-level setting storage. + +void set_log_level(unsigned int level) +{ + opt_auth_win_log_level= level; +} + + +unsigned int get_log_level(void) +{ + return opt_auth_win_log_level; +} From 1e7f06371a05bc7b3d8244536a85408187e9e58d Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Wed, 7 Sep 2011 14:03:17 -0400 Subject: [PATCH 077/143] BUG#12929345 : Execution aborts without any messages (Windows only) This patch adds the length of the buffer in the strncat operation to prevent buffer overrun. --- client/mysql_plugin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index ec3dc64f0d8..406366efd51 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -851,9 +851,9 @@ static int process_options(int argc, char *argv[], char *operation) strncpy(buff, opt_basedir, sizeof(buff) - 1); #ifdef __WIN__ - strncat(buff, "/", sizeof(buff) - 1); + strncat(buff, "/", sizeof(buff) - strlen(buff) - 1); #else - strncat(buff, FN_DIRSEP, sizeof(buff) - 1); + strncat(buff, FN_DIRSEP, sizeof(buff) - strlen(buff) - 1); #endif buff[sizeof(buff) - 1]= 0; my_delete(opt_basedir, MYF(0)); From a5267797553519d1fcaaf51ff070d53cf525dc79 Mon Sep 17 00:00:00 2001 From: Daniel Fischer Date: Thu, 8 Sep 2011 09:36:06 +0200 Subject: [PATCH 078/143] add mysql_plugin man page to spec file --- support-files/mysql.spec.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index b32a7dd836c..4b0c6438199 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -984,6 +984,7 @@ echo "=====" >> $STATUS_HISTORY %doc %attr(644, root, man) %{_mandir}/man1/replace.1* %doc %attr(644, root, man) %{_mandir}/man1/resolve_stack_dump.1* %doc %attr(644, root, man) %{_mandir}/man1/resolveip.1* +%doc %attr(644, root, man) %{_mandir}/man1/mysql_plugin.1* %ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf @@ -1111,6 +1112,10 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Thu Sep 08 2011 Daniel Fischer + +- Add mysql_plugin man page. + * Fri Aug 12 2011 Daniel Fischer - Source plugin library files list from cmake-generated file. From 427e7caa8ea86a1d16dda6900220b226b2b57237 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 8 Sep 2011 11:10:26 +0100 Subject: [PATCH 079/143] BUG#12818224: 61921: WRITETRAXINBINLOG SHOULD BE WRITETRANXINBINLOG IN SEMISYNC_MASTER.CC Fixing typo: writeTraxInBinlog() => writeTranxInBinlog() . Additionally, fixed identation. --- plugin/semisync/semisync_master.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index 1f92c60913e..1be876d0f1b 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -312,18 +312,18 @@ int ActiveTranx::clear_active_tranx_nodes(const char *log_file_name, * The most important functions during semi-syn replication listed: * * Master: - * . reportReplyBinlog(): called by the binlog dump thread when it receives - * the slave's status information. - * . updateSyncHeader(): based on transaction waiting information, decide - * whether to request the slave to reply. - * . writeTraxInBinlog(): called by the transaction thread when it finishes - * writing all transaction events in binlog. - * . commitTrx(): transaction thread wait for the slave reply. + * . reportReplyBinlog(): called by the binlog dump thread when it receives + * the slave's status information. + * . updateSyncHeader(): based on transaction waiting information, decide + * whether to request the slave to reply. + * . writeTranxInBinlog(): called by the transaction thread when it finishes + * writing all transaction events in binlog. + * . commitTrx(): transaction thread wait for the slave reply. * * Slave: * . slaveReadSyncHeader(): read the semi-sync header from the master, get the - * sync status and get the payload for events. - * . slaveReply(): reply to the master about the replication progress. + * sync status and get the payload for events. + * . slaveReply(): reply to the master about the replication progress. * ******************************************************************************/ From 132f023b087da9bdf2c1c9c53d4e3da80bcd5f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Sep 2011 15:54:15 +0300 Subject: [PATCH 080/143] Bug#11766591 59733: POSSIBLE DEADLOCK WHEN BUFFERED CHANGES ARE DISCARDED Tweak the faulty UNIV_SYNC_DEBUG diagnostics a little bit more. ibuf_add_free_page(): Lower the latching order of the newly allocated page only after acquiring the ibuf_mutex. --- storage/innobase/ibuf/ibuf0ibuf.c | 8 ++++---- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 71ecc7ec49f..8f151e39958 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1683,14 +1683,14 @@ ibuf_add_free_page( page = buf_page_get(space, page_no, RW_X_LATCH, &mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); -#endif /* UNIV_SYNC_DEBUG */ - ibuf_enter(); mutex_enter(&ibuf_mutex); +#ifdef UNIV_SYNC_DEBUG + buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); +#endif /* UNIV_SYNC_DEBUG */ + root = ibuf_tree_root_get(ibuf_data, space, &mtr); /* Add the page to the free list and update the ibuf size data */ diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index effd7b9572b..7aaf8f95bc5 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -1766,16 +1766,15 @@ ibuf_add_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); + ibuf_enter(); + mutex_enter(&ibuf_mutex); + + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); } - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - root = ibuf_tree_root_get(&mtr); /* Add the page to the free list and update the ibuf size data */ From 8c545acd5367950d3d03590880781089040016e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Sep 2011 16:10:24 +0300 Subject: [PATCH 081/143] Bug#12948130 UNNECESSARY X-LOCKING OF ADAPTIVE HASH INDEX (BTR_SEARCH_LATCH) InnoDB acquires an x-latch on btr_search_latch for certain in-place updates that do affect the adaptive hash index. These operations do not really need to be protected by the btr_search_latch: * updating DB_TRX_ID * updating DB_ROLL_PTR * updating PAGE_MAX_TRX_ID * updating the delete-mark flag rb:750 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 5 ++ storage/innodb_plugin/btr/btr0cur.c | 61 ++++++++++++----------- storage/innodb_plugin/include/page0page.h | 5 +- storage/innodb_plugin/include/row0upd.ic | 5 -- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index a29aaf2077e..130a0f9afa2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-08 The InnoDB Team + + * btr/btr0cur.c, include/page0page.h, include/row0upd.ic: + Fix Bug#12948130 UNNECESSARY X-LOCKING OF ADAPTIVE HASH INDEX + 2011-09-06 The InnoDB Team * buf/buf0buddy.c: diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index f1c2c2ddd5e..4baa21d7c71 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -1727,6 +1727,7 @@ btr_cur_update_in_place( roll_ptr_t roll_ptr = ut_dulint_zero; trx_t* trx; ulint was_delete_marked; + ibool is_hashed; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; @@ -1768,7 +1769,21 @@ btr_cur_update_in_place( return(err); } - if (block->is_hashed) { + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_rec_sys_fields(rec, NULL, + index, offsets, trx, roll_ptr); + } + + was_delete_marked = rec_get_deleted_flag( + rec, page_is_comp(buf_block_get_frame(block))); + + is_hashed = block->is_hashed; + + if (is_hashed) { + /* TO DO: Can we skip this if none of the fields + index->search_info->curr_n_fields + are being updated? */ + /* The function row_upd_changes_ord_field_binary works only if the update vector was built for a clustered index, we must NOT call it if index is secondary */ @@ -1784,17 +1799,9 @@ btr_cur_update_in_place( rw_lock_x_lock(&btr_search_latch); } - if (!(flags & BTR_KEEP_SYS_FLAG)) { - row_upd_rec_sys_fields(rec, NULL, - index, offsets, trx, roll_ptr); - } - - was_delete_marked = rec_get_deleted_flag( - rec, page_is_comp(buf_block_get_frame(block))); - row_upd_rec_in_place(rec, index, offsets, update, page_zip); - if (block->is_hashed) { + if (is_hashed) { rw_lock_x_unlock(&btr_search_latch); } @@ -2520,7 +2527,8 @@ btr_cur_parse_del_mark_set_clust_rec( /* We do not need to reserve btr_search_latch, as the page is only being recovered, and there cannot be a hash index to - it. */ + it. Besides, these fields are being updated in place + and the adaptive hash index does not depend on them. */ btr_rec_set_deleted_flag(rec, page_zip, val); @@ -2600,9 +2608,9 @@ btr_cur_del_mark_set_clust_rec( return(err); } - if (block->is_hashed) { - rw_lock_x_lock(&btr_search_latch); - } + /* The btr_search_latch is not needed here, because + the adaptive hash index does not depend on the delete-mark + and the delete-mark is being updated in place. */ page_zip = buf_block_get_page_zip(block); @@ -2616,10 +2624,6 @@ btr_cur_del_mark_set_clust_rec( index, offsets, trx, roll_ptr); } - if (block->is_hashed) { - rw_lock_x_unlock(&btr_search_latch); - } - btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx, roll_ptr, mtr); @@ -2695,7 +2699,8 @@ btr_cur_parse_del_mark_set_sec_rec( /* We do not need to reserve btr_search_latch, as the page is only being recovered, and there cannot be a hash index to - it. */ + it. Besides, the delete-mark flag is being updated in place + and the adaptive hash index does not depend on it. */ btr_rec_set_deleted_flag(rec, page_zip, val); } @@ -2743,16 +2748,11 @@ btr_cur_del_mark_set_sec_rec( ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(cursor->index->table)); - if (block->is_hashed) { - rw_lock_x_lock(&btr_search_latch); - } - + /* We do not need to reserve btr_search_latch, as the + delete-mark flag is being updated in place and the adaptive + hash index does not depend on it. */ btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val); - if (block->is_hashed) { - rw_lock_x_unlock(&btr_search_latch); - } - btr_cur_del_mark_set_sec_rec_log(rec, val, mtr); return(DB_SUCCESS); @@ -2772,8 +2772,11 @@ btr_cur_del_unmark_for_ibuf( uncompressed */ mtr_t* mtr) /*!< in: mtr */ { - /* We do not need to reserve btr_search_latch, as the page has just - been read to the buffer pool and there cannot be a hash index to it. */ + /* We do not need to reserve btr_search_latch, as the page + has just been read to the buffer pool and there cannot be + a hash index to it. Besides, the delete-mark flag is being + updated in place and the adaptive hash index does not depend + on it. */ btr_rec_set_deleted_flag(rec, page_zip, FALSE); diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index 9099fd7b65d..caf4cee2c57 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -68,10 +68,7 @@ typedef byte page_header_t; #define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified a record on the page; a dulint; defined only in secondary indexes and in the insert buffer - tree; NOTE: this may be modified only - when the thread has an x-latch to the page, - and ALSO an x-latch to btr_search_latch - if there is a hash index to the page! */ + tree */ #define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page header which are set in a page create */ /*----*/ diff --git a/storage/innodb_plugin/include/row0upd.ic b/storage/innodb_plugin/include/row0upd.ic index 0894ed373b0..11db82f64da 100644 --- a/storage/innodb_plugin/include/row0upd.ic +++ b/storage/innodb_plugin/include/row0upd.ic @@ -157,11 +157,6 @@ row_upd_rec_sys_fields( { ut_ad(dict_index_is_clust(index)); ut_ad(rec_offs_validate(rec, index, offsets)); -#ifdef UNIV_SYNC_DEBUG - if (!rw_lock_own(&btr_search_latch, RW_LOCK_EX)) { - ut_ad(!buf_block_align(rec)->is_hashed); - } -#endif /* UNIV_SYNC_DEBUG */ if (UNIV_LIKELY_NULL(page_zip)) { ulint pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID); From 13fefeb04ade34418cd9d99aa93bffb69fdae27e Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Fri, 9 Sep 2011 10:07:24 +0300 Subject: [PATCH 082/143] Disable the prefetch code in the InnoDB internal SQL parser. This change is a followup to vasil.dimov@oracle.com-20110907145810-v98kldmho23vhhic which triggered the usage of the prefetch and valgrind tests spat lots of warnings. The prefetch code will be removed. Discussed with: Marko (over IM) --- storage/innodb_plugin/row/row0sel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index 241584eaa20..aa3f6283c4f 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -63,7 +63,13 @@ Created 12/19/1997 Heikki Tuuri /* Number of rows fetched, after which to start prefetching; MySQL interface has another parameter */ -#define SEL_PREFETCH_LIMIT 1 +/* The prefetch code in the internal SQL is disabled because it has probably +never been used and has been found to contain a memory leak and a bug of +accessing uninitialized memory. Some simple performance tests show that +disabling it makes no difference in performance. It will be removed, but +until the removal happens we disable it by setting SEL_PREFETCH_LIMIT to a +high value. */ +#define SEL_PREFETCH_LIMIT 1000000000 /* When a select has accessed about this many pages, it returns control back to que_run_threads: this is to allow canceling runaway queries */ From 8433c8ce61956fdeea45a55c7262bf509aaefb0d Mon Sep 17 00:00:00 2001 From: Chuck Bell Date: Fri, 9 Sep 2011 10:39:44 -0400 Subject: [PATCH 083/143] BUG#12929631 : Execute crashes with --verbose output (Windows) This patch corrects an error encountered in PB where Windows machines are built in release mode have an extraneous parameter added in place of the --console option. This is caused by the insert of '(null' instead of an empty string. In non-debug mode, the string is explicitly set to an empty string. Patch also fixes a result mismatch on Windows machines. --- client/mysql_plugin.c | 2 ++ mysql-test/t/mysql_plugin.test | 1 + 2 files changed, 3 insertions(+) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c index 406366efd51..825c962c486 100644 --- a/client/mysql_plugin.c +++ b/client/mysql_plugin.c @@ -1169,6 +1169,8 @@ static int bootstrap_server(char *server_path, char *bootstrap_file) if (opt_verbose) verbose_str= "--console"; + else + verbose_str= ""; if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || has_spaces(bootstrap_file)) format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index b07ce40e43a..09615ec8f00 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -224,6 +224,7 @@ let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MY --echo # Attempt to use bad paths - basedir --echo # let $MYSQL_PLUGIN_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$PLUGIN_DIR --mysqld=$MYSQLD_BASEDIR --my-print-defaults=$MYSQL_MY_PRINT_DEFAULTS_BASEDIR; +replace_result "/basedir_not_there//" "/basedir_not_there/"; --error 1,2,256 --exec $MYSQL_PLUGIN_CMD DISABLE daemon_example 2>&1 From cc496eb7466487747d26d272f0559df9a07f2e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 12 Sep 2011 10:12:15 +0300 Subject: [PATCH 084/143] Bug#12601439 CONSISTENT READ FAILURE IN COLUMN PREFIX INDEX When there is a secondary index on a column prefix of an externally stored column and an entry in the secondary index is shorter than the reserved prefix length, it should mean that the secondary index entry is holding the complete column value. When comparing this secondary index column value to the column in the clustered index row, we must compare the entire prefix that was fetched from the clustered index. The bug was that we would just compare that the column in the clustered index starts with the value found in the secondary index column. This bug affects only the InnoDB Barracuda formats (ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED), in which columns that are stored off-page in the clustered index do not contain any prefix in the clustered index record. row_sel_sec_rec_is_for_blob(): Add the parameter prefix_len, for ifield->prefix_len. Add some assertions. Sorry, I did not manage to produce a test case. This patch does produce correct results on the data set that Michael isolated on our test machine. That was with the purge and background rollback suspended, because they would make the bug go away. rb:760 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/row/row0sel.c | 20 +++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 130a0f9afa2..ff6bd10dbe6 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-12 The InnoDB Team + + * row/row0sel.c: + Fix Bug#12601439 CONSISTENT READ FAILURE IN COLUMN PREFIX INDEX + 2011-09-08 The InnoDB Team * btr/btr0cur.c, include/page0page.h, include/row0upd.ic: diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index aa3f6283c4f..c9b409cbedd 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -107,12 +107,17 @@ row_sel_sec_rec_is_for_blob( ulint clust_len, /*!< in: length of clust_field */ const byte* sec_field, /*!< in: column in secondary index */ ulint sec_len, /*!< in: length of sec_field */ + ulint prefix_len, /*!< in: index column prefix length + in bytes */ ulint zip_size) /*!< in: compressed page size, or 0 */ { ulint len; byte buf[DICT_MAX_INDEX_COL_LEN]; ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE); + ut_ad(prefix_len >= sec_len); + ut_ad(prefix_len > 0); + ut_a(prefix_len <= sizeof buf); if (UNIV_UNLIKELY (!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE, @@ -124,7 +129,7 @@ row_sel_sec_rec_is_for_blob( return(FALSE); } - len = btr_copy_externally_stored_field_prefix(buf, sizeof buf, + len = btr_copy_externally_stored_field_prefix(buf, prefix_len, zip_size, clust_field, clust_len); @@ -138,7 +143,7 @@ row_sel_sec_rec_is_for_blob( } len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen, - sec_len, len, (const char*) buf); + prefix_len, len, (const char*) buf); return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len)); } @@ -225,11 +230,20 @@ row_sel_sec_rec_is_for_clust_rec( if (rec_offs_nth_extern(clust_offs, clust_pos) && len < sec_len) { + /* This function should never be + invoked on an Antelope format table, + because they should always contain + enough prefix in the clustered index + record. */ + ut_ad(dict_table_get_format(clust_index->table) + >= DICT_TF_FORMAT_ZIP); + if (!row_sel_sec_rec_is_for_blob( col->mtype, col->prtype, col->mbminlen, col->mbmaxlen, clust_field, clust_len, sec_field, sec_len, + ifield->prefix_len, dict_table_zip_size( clust_index->table))) { goto inequal; From b82d6043b325bfae6c5a2c1f287f83ecdcd821ed Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 12 Sep 2011 14:16:38 +0200 Subject: [PATCH 085/143] Add support for RHEL6 and OL6. --- support-files/mysql.spec.sh | 73 +++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 0475f132b41..3396717034a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -139,43 +139,62 @@ %endif %endif %else - %if %(test -f /etc/redhat-release && echo 1 || echo 0) - %define rhelver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') - %if "%rhelver" == "4" - %define distro_description Red Hat Enterprise Linux 4 - %define distro_releasetag rhel4 + %if %(test -f /etc/oracle-release && echo 1 || echo 0) + %define elver %(rpm -qf --qf '%%{version}\\n' /etc/enterprise-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') + %if "%elver" == "6" + %define distro_description Oracle Linux 6 + %define distro_releasetag el6 %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else - %if "%rhelver" == "5" - %define distro_description Red Hat Enterprise Linux 5 - %define distro_releasetag rhel5 - %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel - %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools - %else - %{error:Red Hat Enterprise Linux %{rhelver} is unsupported} - %endif + %{error:Oracle Linux %{oelver} is unsupported} %endif %else - %if %(test -f /etc/SuSE-release && echo 1 || echo 0) - %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release) - %if "%susever" == "10" - %define distro_description SUSE Linux Enterprise Server 10 - %define distro_releasetag sles10 - %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client readline-devel zlib-devel - %define distro_requires aaa_base coreutils grep procps pwdutils + %if %(test -f /etc/redhat-release && echo 1 || echo 0) + %define rhelver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') + %if "%rhelver" == "4" + %define distro_description Red Hat Enterprise Linux 4 + %define distro_releasetag rhel4 + %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel + %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else - %if "%susever" == "11" - %define distro_description SUSE Linux Enterprise Server 11 - %define distro_releasetag sles11 - %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client procps pwdutils readline-devel zlib-devel - %define distro_requires aaa_base coreutils grep procps pwdutils + %if "%rhelver" == "5" + %define distro_description Red Hat Enterprise Linux 5 + %define distro_releasetag rhel5 + %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel + %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else - %{error:SuSE %{susever} is unsupported} + %if "%rhelver" == "6" + %define distro_description Red Hat Enterprise Linux 6 + %define distro_releasetag rhel6 + %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel + %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools + %else + %{error:Red Hat Enterprise Linux %{rhelver} is unsupported} + %endif %endif %endif %else - %{error:Unsupported distribution} + %if %(test -f /etc/SuSE-release && echo 1 || echo 0) + %define susever %(rpm -qf --qf '%%{version}\\n' /etc/SuSE-release) + %if "%susever" == "10" + %define distro_description SUSE Linux Enterprise Server 10 + %define distro_releasetag sles10 + %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client readline-devel zlib-devel + %define distro_requires aaa_base coreutils grep procps pwdutils + %else + %if "%susever" == "11" + %define distro_description SUSE Linux Enterprise Server 11 + %define distro_releasetag sles11 + %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client procps pwdutils readline-devel zlib-devel + %define distro_requires aaa_base coreutils grep procps pwdutils + %else + %{error:SuSE %{susever} is unsupported} + %endif + %endif + %else + %{error:Unsupported distribution} + %endif %endif %endif %endif From 741efeedb59c02e0c239779cc65b112e07adf417 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 12 Sep 2011 20:43:36 +0200 Subject: [PATCH 086/143] Fix typos in last. --- support-files/mysql.spec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 3396717034a..5e999793b5e 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -140,14 +140,14 @@ %endif %else %if %(test -f /etc/oracle-release && echo 1 || echo 0) - %define elver %(rpm -qf --qf '%%{version}\\n' /etc/enterprise-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') + %define elver %(rpm -qf --qf '%%{version}\\n' /etc/oracle-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') %if "%elver" == "6" %define distro_description Oracle Linux 6 %define distro_releasetag el6 %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else - %{error:Oracle Linux %{oelver} is unsupported} + %{error:Oracle Linux %{elver} is unsupported} %endif %else %if %(test -f /etc/redhat-release && echo 1 || echo 0) From 3436169892e8aa57128d8046631bf381b75b113d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 13 Sep 2011 09:18:34 +0300 Subject: [PATCH 087/143] Hopefully final fix of Bug#11766591 59733: Possible deadlock when buffered changes are to be discarded ibuf_add_free_page(): Lower the latching order of the newly allocated page to SYNC_IBUF_TREE_NODE_NEW after latching the insert buffer tree root. This bug always was bogus UNIV_SYNC_DEBUG alarm. The function buf_block_dbg_add_level() is a no-op unless UNIV_SYNC_DEBUG is defined. --- storage/innobase/ibuf/ibuf0ibuf.c | 4 ++-- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 8f151e39958..1406b2de4e9 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1687,12 +1687,12 @@ ibuf_add_free_page( mutex_enter(&ibuf_mutex); + root = ibuf_tree_root_get(ibuf_data, space, &mtr); + #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ - root = ibuf_tree_root_get(ibuf_data, space, &mtr); - /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index 7aaf8f95bc5..e4d8f79a944 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -1770,13 +1770,13 @@ ibuf_add_free_page(void) mutex_enter(&ibuf_mutex); + root = ibuf_tree_root_get(&mtr); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); } - root = ibuf_tree_root_get(&mtr); - /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, From 3690fa63e3c5be50a2d7b276cff24f26f06fb6f5 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 13 Sep 2011 12:32:53 +0200 Subject: [PATCH 088/143] Bug #58241 Please exclude make_binary_distribution from the distribution With cmake (5.5 and up), "make package" will do it, or cpack. The (generated) "scripts/make_binary_distribution" is just a wrapper around a "cpack" call, with path names set at build time. Similar, "make_win_bin_dist" is not needed any more. scripts/CMakeLists.txt: Cleanup: Append a trailing newline when generating "make_binary_distribution" (which is just a wrapper around a "cpack" call). support-files/mysql.spec.sh: "make_win_bin_dist" is removed from the sources, so its man page is gone, and it need not be removed when creating the RPMs. --- scripts/CMakeLists.txt | 4 +- scripts/make_binary_distribution.sh | 342 ---------------------- scripts/make_win_bin_dist | 425 ---------------------------- support-files/mysql.spec.sh | 6 +- 4 files changed, 7 insertions(+), 770 deletions(-) delete mode 100644 scripts/make_binary_distribution.sh delete mode 100755 scripts/make_win_bin_dist diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 2efb348fcd5..424d92e31e1 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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 @@ -65,7 +65,7 @@ ADD_CUSTOM_TARGET(GenFixPrivs IF(UNIX) FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_binary_distribution - "cd ${CMAKE_BINARY_DIR} && '${CMAKE_CPACK_COMMAND}' -G TGZ --config CPackConfig.cmake" ) + "cd ${CMAKE_BINARY_DIR} && '${CMAKE_CPACK_COMMAND}' -G TGZ --config CPackConfig.cmake\n" ) EXECUTE_PROCESS( COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/make_binary_distribution ) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh deleted file mode 100644 index 5ccdb2b914c..00000000000 --- a/scripts/make_binary_distribution.sh +++ /dev/null @@ -1,342 +0,0 @@ -#!/bin/sh -# 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 -# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -############################################################################## -# -# This is a script to create a TAR or ZIP binary distribution out of a -# built source tree. The output file will be put at the top level of -# the source tree, as "mysql-....{tar.gz,zip}" -# -# Note that the structure created by this script is slightly different from -# what a normal "make install" would produce. No extra "mysql" sub directory -# will be created, i.e. no "$prefix/include/mysql", "$prefix/lib/mysql" or -# "$prefix/share/mysql". This is because the build system explicitly calls -# make with pkgdatadir=, etc. -# -# In GNU make/automake terms -# -# "pkglibdir" is set to the same as "libdir" -# "pkgincludedir" is set to the same as "includedir" -# "pkgdatadir" is set to the same as "datadir" -# "pkgplugindir" is set to "$pkglibdir/plugin" -# "pkgsuppdir" is set to "@prefix@/support-files", -# normally the same as "datadir" -# -# The temporary directory path given to "--tmp=" has to be -# absolute and with no spaces. -# -# Note that for best result, the original "make" should be done with -# the same arguments as used for "make install" below, especially the -# 'pkglibdir', as the RPATH should to be set correctly. -# -############################################################################## - -############################################################################## -# -# Read the command line arguments that control this script -# -############################################################################## - -machine=@MACHINE_TYPE@ -system=@SYSTEM_TYPE@ -SOURCE=`pwd` -CP="cp -p" -MV="mv" - -# There are platforms, notably OS X on Intel (x86 + x86_64), -# for which "uname" does not provide sufficient information. -# The value of CFLAGS as used during compilation is the most exact info -# we can get - after all, we care about _what_ we built, not _where_ we did it. -cflags="@CFLAGS@" - -STRIP=1 # Option ignored -SILENT=0 -MALLOC_LIB= -PLATFORM="" -TMP=/tmp -NEW_NAME="" # Final top directory and TAR package name -SUFFIX="" -SHORT_PRODUCT_TAG="" # If don't want server suffix in package name -NDBCLUSTER="" # Option ignored - -for arg do - case "$arg" in - --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; - --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; - --short-product-tag=*) SHORT_PRODUCT_TAG=`echo "$arg" | sed -e "s;--short-product-tag=;;"` ;; - --inject-malloc-lib=*) MALLOC_LIB=`echo "$arg" | sed -e 's;^[^=]*=;;'` ;; - --no-strip) STRIP=0 ;; - --machine=*) machine=`echo "$arg" | sed -e "s;--machine=;;"` ;; - --platform=*) PLATFORM=`echo "$arg" | sed -e "s;--platform=;;"` ;; - --silent) SILENT=1 ;; - --with-ndbcluster) NDBCLUSTER=1 ;; - *) - echo "Unknown argument '$arg'" - exit 1 - ;; - esac -done - -# ---------------------------------------------------------------------- -# Adjust "system" output from "uname" to be more human readable -# ---------------------------------------------------------------------- - -if [ x"$PLATFORM" = x"" ] ; then - # FIXME move this to the build tools - # Remove vendor from $system - system=`echo $system | sed -e 's/[a-z]*-\(.*\)/\1/g'` - - # Map OS names to "our" OS names (eg. darwin6.8 -> osx10.2) - system=`echo $system | sed -e 's/darwin6.*/osx10.2/g'` - system=`echo $system | sed -e 's/darwin7.*/osx10.3/g'` - system=`echo $system | sed -e 's/darwin8.*/osx10.4/g'` - system=`echo $system | sed -e 's/darwin9.*/osx10.5/g'` - system=`echo $system | sed -e 's/\(aix4.3\).*/\1/g'` - system=`echo $system | sed -e 's/\(aix5.1\).*/\1/g'` - system=`echo $system | sed -e 's/\(aix5.2\).*/\1/g'` - system=`echo $system | sed -e 's/\(aix5.3\).*/\1/g'` - system=`echo $system | sed -e 's/osf5.1b/tru64/g'` - system=`echo $system | sed -e 's/linux-gnu/linux/g'` - system=`echo $system | sed -e 's/solaris2.\([0-9]*\)/solaris\1/g'` - system=`echo $system | sed -e 's/sco3.2v\(.*\)/openserver\1/g'` -fi - -# Get the "machine", which really is the CPU architecture (including the size). -# The precedence is: -# 1) use an explicit argument, if given; -# 2) use platform-specific fixes, if there are any (see bug#37808); -# 3) stay with the default (determined during "configure", using predefined macros). - -if [ x"$MACHINE" != x"" ] ; then - machine=$MACHINE -else - case $system in - osx* ) - # Extract "XYZ" from CFLAGS "... -arch XYZ ...", or empty! - cflag_arch=`echo "$cflags" | sed -n -e 's=.* -arch \([^ ]*\) .*=\1=p'` - case "$cflag_arch" in - i386 ) case $system in - osx10.4 ) machine=i686 ;; # Used a different naming - * ) machine=x86 ;; - esac ;; - x86_64 ) machine=x86_64 ;; - ppc ) ;; # No treatment needed with PPC - ppc64 ) ;; - * ) # No matching compiler flag? "--platform" is needed - if [ x"$PLATFORM" != x"" ] ; then - : # See below: "$PLATFORM" will take precedence anyway - elif [ "$system" = "osx10.3" -a -z "$cflag_arch" ] ; then - : # Special case of OS X 10.3, which is PPC-32 only and doesn't use "-arch" - else - echo "On system '$system' only specific '-arch' values are expected." - echo "It is taken from the 'CFLAGS' whose value is:" - echo "$cflags" - echo "'-arch $cflag_arch' is unexpected, and no '--platform' was given: ABORT" - exit 1 - fi ;; - esac # "$cflag_arch" - ;; - esac # $system -fi - -# Combine OS and CPU to the "platform". Again, an explicit argument takes precedence. -if [ x"$PLATFORM" != x"" ] ; then - : -else - PLATFORM="$system-$machine" -fi - -# Print the platform name for build logs -echo "PLATFORM NAME: $PLATFORM" - -# Change the distribution to a long descriptive name -# For the cluster product, concentrate on the second part -VERSION_NAME=@VERSION@ -case $VERSION_NAME in - *-ndb-* ) VERSION_NAME=`echo $VERSION_NAME | sed -e 's/[.0-9]*-ndb-//'` ;; -esac -if [ x"$SHORT_PRODUCT_TAG" != x"" ] ; then - NEW_NAME=mysql-$SHORT_PRODUCT_TAG-$VERSION_NAME-$PLATFORM$SUFFIX -else - NEW_NAME=mysql@MYSQL_SERVER_SUFFIX@-$VERSION_NAME-$PLATFORM$SUFFIX -fi - -# ---------------------------------------------------------------------- -# Define BASE, and remove the old BASE directory if any -# ---------------------------------------------------------------------- -BASE=$TMP/my_dist$SUFFIX -if [ -d $BASE ] ; then - rm -rf $BASE -fi - -# ---------------------------------------------------------------------- -# Find the TAR to use -# ---------------------------------------------------------------------- - -# This is needed to prefer GNU tar over platform tar because that can't -# always handle long filenames - -PATH_DIRS=`echo $PATH | \ - sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' ` - -which_1 () -{ - for cmd - do - for d in $PATH_DIRS - do - for file in $d/$cmd - do - if [ -x $file -a ! -d $file ] ; then - echo $file - exit 0 - fi - done - done - done - exit 1 -} - -tar=`which_1 gnutar gtar` -if [ $? -ne 0 -o x"$tar" = x"" ] ; then - tar=tar -fi - - -############################################################################## -# -# Handle the Unix/Linux packaging using "make install" -# -############################################################################## - -# ---------------------------------------------------------------------- -# Terminate on any base level error -# ---------------------------------------------------------------------- -set -e - -# ---------------------------------------------------------------------- -# Really ugly, one script, "mysql_install_db", needs prefix set to ".", -# i.e. makes access relative the current directory. This matches -# the documentation, so better not change this. And for another script, -# "mysql.server", we make some relative, others not. -# ---------------------------------------------------------------------- - -cd scripts -rm -f mysql_install_db -@MAKE@ mysql_install_db \ - prefix=. \ - bindir=./bin \ - sbindir=./bin \ - scriptdir=./bin \ - libexecdir=./bin \ - pkgdatadir=./share \ - localstatedir=./data -cd .. - -cd support-files -rm -f mysql.server -@MAKE@ mysql.server \ - bindir=./bin \ - sbindir=./bin \ - scriptdir=./bin \ - libexecdir=./bin \ - pkgdatadir=@pkgdatadir@ -cd .. - -# ---------------------------------------------------------------------- -# Do a install that we later are to pack. Use the same paths as in -# the build for the relevant directories. -# ---------------------------------------------------------------------- -@MAKE@ DESTDIR=$BASE install \ - pkglibdir=@pkglibdir@ \ - pkgincludedir=@pkgincludedir@ \ - pkgdatadir=@pkgdatadir@ \ - pkgplugindir=@pkgplugindir@ \ - pkgsuppdir=@pkgsuppdir@ \ - mandir=@mandir@ \ - infodir=@infodir@ - -# ---------------------------------------------------------------------- -# Rename top directory, and set DEST to the new directory -# ---------------------------------------------------------------------- -mv $BASE@prefix@ $BASE/$NEW_NAME -DEST=$BASE/$NEW_NAME - -# ---------------------------------------------------------------------- -# If we compiled with gcc, copy libgcc.a to the dist as libmygcc.a -# ---------------------------------------------------------------------- -if [ x"@GXX@" = x"yes" ] ; then - gcclib=`@CC@ @CFLAGS@ --print-libgcc-file 2>/dev/null` || true - if [ -z "$gcclib" ] ; then - echo "Warning: Compiler doesn't tell libgcc.a!" - elif [ -f "$gcclib" ] ; then - $CP $gcclib $DEST/lib/libmygcc.a - else - echo "Warning: Compiler result '$gcclib' not found / no file!" - fi -fi - -# If requested, add a malloc library .so into pkglibdir for use -# by mysqld_safe -if [ -n "$MALLOC_LIB" ]; then - cp "$MALLOC_LIB" "$DEST/lib/" -fi - -# FIXME let this script be in "bin/", where it is in the RPMs? -# http://dev.mysql.com/doc/refman/5.1/en/mysql-install-db-problems.html -mkdir $DEST/scripts -mv $DEST/bin/mysql_install_db $DEST/scripts/ - -# Note, no legacy "safe_mysqld" link to "mysqld_safe" in 5.1 - -# Copy readme and license files -cp README Docs/INSTALL-BINARY $DEST/ -if [ -f COPYING ] ; then - cp COPYING $DEST/ -elif [ -f LICENSE.mysql ] ; then - cp LICENSE.mysql $DEST/ -else - echo "ERROR: no license files found" - exit 1 -fi - -# FIXME should be handled by make file, and to other dir -mkdir -p $DEST/bin $DEST/support-files -cp scripts/mysqlaccess.conf $DEST/bin/ -cp support-files/magic $DEST/support-files/ - -# Create empty data directories, set permission (FIXME why?) -mkdir $DEST/data $DEST/data/mysql $DEST/data/test -chmod o-rwx $DEST/data $DEST/data/mysql $DEST/data/test - -# ---------------------------------------------------------------------- -# Create the result tar file -# ---------------------------------------------------------------------- - -echo "Using $tar to create archive" -OPT=cvf -if [ x$SILENT = x1 ] ; then - OPT=cf -fi - -echo "Creating and compressing archive" -rm -f $NEW_NAME.tar.gz -(cd $BASE ; $tar $OPT - $NEW_NAME) | gzip -9 > $NEW_NAME.tar.gz -echo "$NEW_NAME.tar.gz created" - -echo "Removing temporary directory" -rm -rf $BASE -exit 0 diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist deleted file mode 100755 index 00ef9186d48..00000000000 --- a/scripts/make_win_bin_dist +++ /dev/null @@ -1,425 +0,0 @@ -#!/bin/sh -# Copyright (c) 2006, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Exit if failing to copy, we want exact specifications, not -# just "what happen to be built". -set -e - -# ---------------------------------------------------------------------- -# Read first argument that is the base name of the resulting TAR file. -# See usage() function below for a description on the arguments. -# -# NOTE: We will read the rest of the command line later on. -# NOTE: Pattern matching with "{..,..}" can't be used, not portable. -# ---------------------------------------------------------------------- - -# FIXME why "libmysql.dll" installed both in "bin" and "lib/opt"? - -usage() -{ - echo <> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Tue Sep 13 2011 Joerg Bruehe + +- "make_win_bin_dist" and its manual are dropped, cmake does it different. + * Tue Aug 30 2011 Joerg Bruehe - Add the manual page for "mysql_plugin" to the server package. From 37f4deccd0f3c23e7af6c2e5f5f45d5225e1c01d Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 13 Sep 2011 17:18:06 +0300 Subject: [PATCH 089/143] Re-enable the prefetch code in InnoDB internal SQL parser and fix two bugs in it - accessing uninitialized ::len member (thanks, Jimmy!) and a memory leak. This is a followup to vasil.dimov@oracle.com-20110909070724-jvirxnpkbxieauz5 which disabled the prefetch code. --- storage/innodb_plugin/row/row0sel.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index c9b409cbedd..32f21dbe198 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -63,13 +63,7 @@ Created 12/19/1997 Heikki Tuuri /* Number of rows fetched, after which to start prefetching; MySQL interface has another parameter */ -/* The prefetch code in the internal SQL is disabled because it has probably -never been used and has been found to contain a memory leak and a bug of -accessing uninitialized memory. Some simple performance tests show that -disabling it makes no difference in performance. It will be removed, but -until the removal happens we disable it by setting SEL_PREFETCH_LIMIT to a -high value. */ -#define SEL_PREFETCH_LIMIT 1000000000 +#define SEL_PREFETCH_LIMIT 1 /* When a select has accessed about this many pages, it returns control back to que_run_threads: this is to allow canceling runaway queries */ @@ -514,7 +508,7 @@ sel_col_prefetch_buf_alloc( sel_buf = column->prefetch_buf + i; sel_buf->data = NULL; - + sel_buf->len = 0; sel_buf->val_buf_size = 0; } } @@ -539,6 +533,8 @@ sel_col_prefetch_buf_free( mem_free(sel_buf->data); } } + + mem_free(prefetch_buf); } /*********************************************************************//** From e715b761ad520e0bae8edf05c26ad8cd20969f22 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Tue, 13 Sep 2011 16:18:57 +0200 Subject: [PATCH 090/143] Complete support for OL/RH6. --- support-files/mysql.spec.sh | 47 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 78211a4bc38..19595f228ef 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -144,7 +144,7 @@ %if "%elver" == "6" %define distro_description Oracle Linux 6 %define distro_releasetag el6 - %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel + %define distro_buildreq gcc-c++ ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else %{error:Oracle Linux %{elver} is unsupported} @@ -167,7 +167,7 @@ %if "%rhelver" == "6" %define distro_description Red Hat Enterprise Linux 6 %define distro_releasetag rhel6 - %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel + %define distro_buildreq gcc-c++ ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils net-tools %else %{error:Red Hat Enterprise Linux %{rhelver} is unsupported} @@ -463,25 +463,6 @@ mkdir release make ${MAKE_JFLAG} VERBOSE=1 ) -# Use the build root for temporary storage of the shared libraries. -RBR=$RPM_BUILD_ROOT - -# Clean up the BuildRoot first -[ "$RBR" != "/" ] && [ -d "$RBR" ] && rm -rf "$RBR"; - -# For gcc builds, include libgcc.a in the devel subpackage (BUG 4921). This -# needs to be during build phase as $CC is not set during install. -if "$CC" -v 2>&1 | grep '^gcc.version' >/dev/null 2>&1 -then - libgcc=`$CC $CFLAGS --print-libgcc-file` - if [ -f $libgcc ] - then - mkdir -p $RBR%{_libdir}/mysql - install -m 644 $libgcc $RBR%{_libdir}/mysql/libmygcc.a - echo "%{_libdir}/mysql/libmygcc.a" >>optional-files-devel - fi -fi - ############################################################################## %install @@ -504,6 +485,23 @@ install -d $RBR%{_sbindir} make DESTDIR=$RBR install ) +# For gcc builds, include libgcc.a in the devel subpackage (BUG 4921). Do +# this in a sub-shell to ensure we don't pollute the install environment +# with compiler bits. +( + PATH=${MYSQL_BUILD_PATH:-$PATH} + CC=${MYSQL_BUILD_CC:-${CC:-gcc}} + CFLAGS=${MYSQL_BUILD_CFLAGS:-${CFLAGS:-$RPM_OPT_FLAGS}} + if "${CC}" -v 2>&1 | grep '^gcc.version' >/dev/null 2>&1; then + libgcc=`${CC} ${CFLAGS} --print-libgcc-file` + if [ -f ${libgcc} ]; then + mkdir -p $RBR%{_libdir}/mysql + install -m 644 ${libgcc} $RBR%{_libdir}/mysql/libmygcc.a + echo "%{_libdir}/mysql/libmygcc.a" >>optional-files-devel + fi + fi +) + # FIXME: at some point we should stop doing this and just install everything # FIXME: directly into %{_libdir}/mysql - perhaps at the same time as renaming # FIXME: the shared libraries to use libmysql*-$major.$minor.so syntax @@ -1153,6 +1151,13 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Tue Sep 13 2011 Jonathan Perkin + +- Add support for Oracle Linux 6 and Red Hat Enterprise Linux 6. Due to + changes in RPM behaviour ($RPM_BUILD_ROOT is removed prior to %install) + this necessitated a move of the libmygcc.a installation from %build to + %install, which is probably where it belonged in the first place. + * Tue Sep 13 2011 Joerg Bruehe - "make_win_bin_dist" and its manual are dropped, cmake does it different. From d60cdefc0da9e2d5a49499763fdf5577d9fbb609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 14 Sep 2011 15:39:36 +0300 Subject: [PATCH 091/143] Hopefully really final fix of Bug#11766591 59733: Possible deadlock when buffered changes are to be discarded sync_thread_add_level(level = SYNC_IBUF_INDEX_TREE): Relax a too strict condition that the thread must not be holding locks below SYNC_FSP_PAGE. It is perfectly valid to hold any latch above SYNC_IBUF_INDEX_TREE when acquiring the insert buffer tree latch. --- storage/innodb_plugin/sync/sync0sync.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 64aadffdfad..3640e204525 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1258,8 +1258,7 @@ sync_thread_add_level( break; case SYNC_IBUF_INDEX_TREE: if (sync_thread_levels_contain(array, SYNC_FSP)) { - ut_a(sync_thread_levels_g( - array, SYNC_FSP_PAGE - 1, TRUE)); + ut_a(sync_thread_levels_g(array, level - 1, TRUE)); } else { ut_a(sync_thread_levels_g( array, SYNC_IBUF_TREE_NODE - 1, TRUE)); From a238e6ada252aaf8c0f9f146ec46c15ea13309e7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:15:36 +0200 Subject: [PATCH 092/143] Bug #12956584 MYSQLTEST: --ENABLE_X OR --DISABLE_X APPLYING ONLY TO NEXT COMMAND/STMT Added a keyword ONCE to add to those commands Some internal tables to keep track of which properties are temporarily overriden Added tests in mysqltest.test Updates to other tests will be done later --- client/mysqltest.cc | 132 ++++++++++++++++++++++++++-------- mysql-test/r/mysqltest.result | 19 +++++ mysql-test/t/mysqltest.test | 61 +++++++++++++--- 3 files changed, 173 insertions(+), 39 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 903f6a024f7..6b1f6645b09 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -118,6 +118,41 @@ static char **default_argv; static const char *load_default_groups[]= { "mysqltest", "client", 0 }; static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; +/* Info on properties that can be set with --enable_X and --disable_X */ + +struct property { + my_bool *var; /* Actual variable */ + my_bool set; /* Has been set for ONE command */ + my_bool old; /* If set, thus is the old value */ + my_bool reverse; /* Varible is true if disabled */ + const char *env_name; /* Env. variable name */ +}; + +static struct property prop_list[] = { + { &abort_on_error, 0, 1, 0, "$ENABLED_ABORT_ON_ERROR" }, + { &disable_connect_log, 0, 1, 1, "$ENABLED_CONNECT_LOG" }, + { &disable_info, 0, 1, 1, "$ENABLED_INFO" }, + { &display_metadata, 0, 0, 0, "$ENABLED_METADATA" }, + { &ps_protocol, 0, 0, 0, "$ENABLED_PS_PROTOCOL" }, + { &disable_query_log, 0, 0, 1, "$ENABLED_QUERY_LOG" }, + { &disable_result_log, 0, 0, 1, "$ENABLED_RESULT_LOG" }, + { &disable_warnings, 0, 0, 1, "$ENABLED_WARNINGS" } +}; + +static my_bool once_property= FALSE; + +enum enum_prop { + P_ABORT= 0, + P_CONNECT, + P_INFO, + P_META, + P_PS, + P_QUERY, + P_RESULT, + P_WARN, + P_MAX +}; + static uint start_lineno= 0; /* Start line of current command */ static uint my_end_arg= 0; @@ -712,6 +747,7 @@ void handle_error(struct st_command*, unsigned int err_errno, const char *err_error, const char *err_sqlstate, DYNAMIC_STRING *ds); void handle_no_error(struct st_command*); +void revert_properties(); #ifdef EMBEDDED_LIBRARY @@ -1174,6 +1210,7 @@ void handle_command_error(struct st_command *command, uint error) { DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d", command->first_word_len, command->query, error)); + revert_properties(); DBUG_VOID_RETURN; } if (command->expected_errors.count > 0) @@ -1188,6 +1225,7 @@ void handle_command_error(struct st_command *command, uint error) command->first_word_len, command->query, command->expected_errors.err[0].code.errnum); } + revert_properties(); DBUG_VOID_RETURN; } @@ -2267,6 +2305,50 @@ void var_set_errno(int sql_errno) var_set_string("$mysql_errname", get_errname_from_code(sql_errno)); } +/* Functions to handle --disable and --enable properties */ + +void set_once_property(enum_prop prop, my_bool val) +{ + property &pr= prop_list[prop]; + pr.set= 1; + pr.old= *pr.var; + *pr.var= val; + var_set_int(pr.env_name, (val != pr.reverse)); + once_property= TRUE; +} + +void set_property(st_command *command, enum_prop prop, my_bool val) +{ + char* p= command->first_argument; + if (p && !strcmp (p, "ONCE")) + { + command->last_argument= p + 4; + set_once_property(prop, val); + return; + } + property &pr= prop_list[prop]; + *pr.var= val; + pr.set= 0; + var_set_int(pr.env_name, (val != pr.reverse)); +} + +void revert_properties() +{ + if (! once_property) + return; + for (int i= 0; i < (int) P_MAX; i++) + { + property &pr= prop_list[i]; + if (pr.set) + { + *pr.var= pr.old; + pr.set= 0; + var_set_int(pr.env_name, (pr.old != pr.reverse)); + } + } + once_property=FALSE; +} + /* Set variable from the result of a query @@ -4426,6 +4508,7 @@ void do_let(struct st_command *command) var_set(var_name, var_name_end, let_rhs_expr.str, (let_rhs_expr.str + let_rhs_expr.length)); dynstr_free(&let_rhs_expr); + revert_properties(); DBUG_VOID_RETURN; } @@ -7354,6 +7437,7 @@ void handle_error(struct st_command *command, dynstr_append(ds,"Got one of the listed errors\n"); } /* OK */ + revert_properties(); DBUG_VOID_RETURN; } @@ -7381,6 +7465,7 @@ void handle_error(struct st_command *command, command->expected_errors.err[0].code.sqlstate); } + revert_properties(); DBUG_VOID_RETURN; } @@ -7415,6 +7500,7 @@ void handle_no_error(struct st_command *command) command->query, command->expected_errors.err[0].code.sqlstate); } + revert_properties(); DBUG_VOID_RETURN; } @@ -8475,60 +8561,46 @@ int main(int argc, char **argv) case Q_DIRTY_CLOSE: do_close_connection(command); break; case Q_ENABLE_QUERY_LOG: - disable_query_log= 0; - var_set_int("$ENABLED_QUERY_LOG", 1); + set_property(command, P_QUERY, 0); break; case Q_DISABLE_QUERY_LOG: - disable_query_log= 1; - var_set_int("$ENABLED_QUERY_LOG", 0); + set_property(command, P_QUERY, 1); break; case Q_ENABLE_ABORT_ON_ERROR: - abort_on_error= 1; - var_set_int("$ENABLED_ABORT_ON_ERROR", 1); + set_property(command, P_ABORT, 1); break; case Q_DISABLE_ABORT_ON_ERROR: - abort_on_error= 0; - var_set_int("$ENABLED_ABORT_ON_ERROR", 0); + set_property(command, P_ABORT, 0); break; case Q_ENABLE_RESULT_LOG: - disable_result_log= 0; - var_set_int("$ENABLED_RESULT_LOG", 1); + set_property(command, P_RESULT, 0); break; case Q_DISABLE_RESULT_LOG: - disable_result_log=1; - var_set_int("$ENABLED_RESULT_LOG", 0); + set_property(command, P_RESULT, 1); break; case Q_ENABLE_CONNECT_LOG: - disable_connect_log=0; - var_set_int("$ENABLED_CONNECT_LOG", 1); + set_property(command, P_CONNECT, 0); break; case Q_DISABLE_CONNECT_LOG: - disable_connect_log=1; - var_set_int("$ENABLED_CONNECT_LOG", 0); + set_property(command, P_CONNECT, 1); break; case Q_ENABLE_WARNINGS: - disable_warnings= 0; - var_set_int("$ENABLED_WARNINGS", 1); + set_property(command, P_WARN, 0); break; case Q_DISABLE_WARNINGS: - disable_warnings= 1; - var_set_int("$ENABLED_WARNINGS", 0); + set_property(command, P_WARN, 1); break; case Q_ENABLE_INFO: - disable_info= 0; - var_set_int("$ENABLED_INFO", 1); + set_property(command, P_INFO, 0); break; case Q_DISABLE_INFO: - disable_info= 1; - var_set_int("$ENABLED_INFO", 0); + set_property(command, P_INFO, 1); break; case Q_ENABLE_METADATA: - display_metadata= 1; - var_set_int("$ENABLED_METADATA", 1); + set_property(command, P_META, 1); break; case Q_DISABLE_METADATA: - display_metadata= 0; - var_set_int("$ENABLED_METADATA", 0); + set_property(command, P_META, 0); break; case Q_SOURCE: do_source(command); break; case Q_SLEEP: do_sleep(command, 0); break; @@ -8744,12 +8816,12 @@ int main(int argc, char **argv) do_set_charset(command); break; case Q_DISABLE_PS_PROTOCOL: - ps_protocol_enabled= 0; + set_property(command, P_PS, 0); /* Close any open statements */ close_statements(); break; case Q_ENABLE_PS_PROTOCOL: - ps_protocol_enabled= ps_protocol; + set_property(command, P_PS, 1); break; case Q_DISABLE_RECONNECT: set_reconnect(&cur_con->mysql, 0); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 9d000e6f782..2dfb0e88f6e 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -160,6 +160,25 @@ after_--enable_abort_on_error select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1064... +garbage; +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 'garbage' at line 1 +select 2; +select 3; +3 +3 +select 5; +ERROR 42S02: Table 'test.t1' doesn't exist +select 7; +7 +7 +mysqltest: At line 1: End of line junk detected: "OCNE" +connect con1,localhost,root,,; +select 5 from t1; +lower +case +name +abc +xyz hello hello ;;;;;;;; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 9fa41b9eb51..6279a392119 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -383,6 +383,54 @@ select 3 from t1 ; --error 1 --exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test --enable and --disable with ONCE +# ---------------------------------------------------------------------------- + +--disable_abort_on_error ONCE +garbage; +--disable_abort_on_error ONCE +--remove_file DoesNotExist + +--disable_result_log +select 2; +--enable_result_log ONCE +select 3; +select 5; +--enable_result_log + +# ---------------------------------------------------------------------------- +# Test cumulative ONCE +# ---------------------------------------------------------------------------- + +--disable_abort_on_error ONCE +--disable_query_log ONCE +select 3 from t1; +select 7; + +--error 1 +--exec echo "--disable_info OCNE" | $MYSQL_TEST 2>&1 + +--enable_connect_log ONCE +connect (con1,localhost,root,,); +connection default; +disconnect con1; + +# ---------------------------------------------------------------------------- +# Test ONCE can be combined with --error or modifiers like lowercase +# ---------------------------------------------------------------------------- + +--disable_result_log ONCE +--error ER_NO_SUCH_TABLE +select 5 from t1; + +--disable_query_log ONCE +--lowercase_result +select "CASE" as "LOWER"; + +--sorted_result +--disable_query_log ONCE +select "xyz" as name union select "abc" as name order by name desc; # ---------------------------------------------------------------------------- # Test comments @@ -952,10 +1000,9 @@ while ($outer) --source $MYSQLTEST_VARDIR/tmp/sourced.inc --error ER_NO_SUCH_TABLE SELECT * from nowhere; - --disable_abort_on_error + --disable_abort_on_error ONCE # Statement giving a different error, to make sure we don't mask it SELECT * FROM nowhere else; - --enable_abort_on_error } dec $outer; inc $ifval; @@ -1104,9 +1151,8 @@ system echo "hej" > /dev/null; --error 1 --exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 ---disable_abort_on_error +--disable_abort_on_error ONCE system NonExistsinfComamdn 2> /dev/null; ---enable_abort_on_error # ---------------------------------------------------------------------------- @@ -2517,10 +2563,9 @@ INSERT INTO t1 SELECT f1 - 64 FROM t1; INSERT INTO t1 SELECT f1 - 128 FROM t1; INSERT INTO t1 SELECT f1 - 256 FROM t1; INSERT INTO t1 SELECT f1 - 512 FROM t1; ---disable_result_log +--disable_result_log ONCE --sorted_result SELECT * FROM t1; ---enable_result_log DROP TABLE t1; # ---------------------------------------------------------------------------- @@ -2568,11 +2613,9 @@ SELECT 0 as "WILL NOT lower case --exec $MYSQL_TEST --help 2>&1 > /dev/null --exec $MYSQL_TEST --version 2>&1 > /dev/null --enable_query_log ---disable_abort_on_error +--disable_abort_on_error ONCE --error 1 --exec $MYSQL_TEST a b c 2>&1 > /dev/null ---enable_abort_on_error ---enable_query_log # ---------------------------------------------------------------------------- # test for query_get_value From 52960624d350359c67a333fb09c3a93465116668 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:19:24 +0200 Subject: [PATCH 093/143] Bug #12793118 MYSQLTEST: --ERROR AND --DISABLE_ABORT_ON_ERROR DO NOT WORK FOR SQL IN COMMANDS Call handle_error() instead of die() when evaluating these Must remember "current command" with link to errors to ignore Added test cases to mysqltest.test --- client/mysqltest.cc | 27 ++++++++++++++++++++++----- mysql-test/r/mysqltest.result | 11 +++++++++-- mysql-test/t/mysqltest.test | 25 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 9985b70fcbc..593bb8ea290 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -451,6 +451,7 @@ TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; DYNAMIC_STRING ds_res; +struct st_command *curr_command= 0; char builtin_echo[FN_REFLEN]; @@ -2212,9 +2213,16 @@ void var_query_set(VAR *var, const char *query, const char** query_end) init_dynamic_string(&ds_query, 0, (end - query) + 32, 256); do_eval(&ds_query, query, end, FALSE); - if (mysql_real_query(mysql, ds_query.str, ds_query.length)) - die("Error running query '%s': %d %s", ds_query.str, - mysql_errno(mysql), mysql_error(mysql)); + if (mysql_real_query(mysql, ds_query.str, ds_query.length)) + { + handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); + /* If error was acceptable, return empty string */ + dynstr_free(&ds_query); + eval_expr(var, "", 0); + DBUG_VOID_RETURN; + } + if (!(res= mysql_store_result(mysql))) die("Query '%s' didn't return a result set", ds_query.str); dynstr_free(&ds_query); @@ -2315,8 +2323,15 @@ void var_set_query_get_value(struct st_command *command, VAR *var) /* Run the query */ if (mysql_real_query(mysql, ds_query.str, ds_query.length)) - die("Error running query '%s': %d %s", ds_query.str, - mysql_errno(mysql), mysql_error(mysql)); + { + handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); + /* If error was acceptable, return empty string */ + dynstr_free(&ds_query); + eval_expr(var, "", 0); + DBUG_VOID_RETURN; + } + if (!(res= mysql_store_result(mysql))) die("Query '%s' didn't return a result set", ds_query.str); @@ -8147,6 +8162,8 @@ int main(int argc, char **argv) { command->last_argument= command->first_argument; processed = 1; + /* Need to remember this for handle_error() */ + curr_command= command; switch (command->type) { case Q_CONNECT: do_connect(command); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index a16b3ec2670..ecfd526ebc9 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -135,6 +135,10 @@ select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1000... +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 'garbage' at line 1 + is empty +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 'nonsense' at line 1 + is empty garbage ; 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 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -143,6 +147,9 @@ after_--enable_abort_on_error select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1064... + is empty + is empty +"Yes it's empty" hello hello ;;;;;;;; @@ -315,7 +322,7 @@ insert into t1 values ('$dollar'); $dollar `select 42` drop table t1; -mysqltest: At line 1: Error running query 'failing query': 1064 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 'failing query' at line 1 +mysqltest: At line 1: query 'let $var2= `failing query`' failed: 1064: 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 'failing query' at line 1 mysqltest: At line 1: Missing required argument 'filename' to command 'source' mysqltest: At line 1: Could not open './non_existingFile' for reading, errno: 2 mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": @@ -813,7 +820,7 @@ mysqltest: At line 1: Could not find column 'column_not_exists' in the result of mysqltest: At line 1: Query 'SET @A = 1' didn't return a result set mysqltest: At line 1: Could not find column '1 AS B' in the result of 'SELECT 1 AS A' value= No such row -mysqltest: At line 1: Error running query 'SHOW COLNS FROM t1': 1064 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 'COLNS FROM t1' at line 1 +mysqltest: At line 1: query 'let $value= query_get_value(SHOW COLNS FROM t1, Field, 1)' failed: 1064: 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 'COLNS FROM t1' at line 1 Field Type Null Key Default Extra a int(11) YES -><- NULL diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 52dfd8e86d3..7b897117b9b 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -334,6 +334,14 @@ eval select $mysql_errno as "after_!errno_masked_error" ; exit(2); EOF +# ---------------------------------------------------------------------------- +# Check backtick and query_get_value, result should be empty +# ---------------------------------------------------------------------------- +let $empty= `garbage`; +echo $empty is empty; +let $empty= query_get_value(nonsense, blabla, 1); +echo $empty is empty; + # ---------------------------------------------------------------------------- # Switch the abort on error on and check the effect on $mysql_errno # ---------------------------------------------------------------------------- @@ -364,6 +372,23 @@ select 3 from t1 ; --exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test --error with backtick operator or query_get_value +# ---------------------------------------------------------------------------- + +--error 0,ER_NO_SUCH_TABLE +let $empty= `SELECT foo from bar`; +echo $empty is empty; + +--error 0,ER_BAD_FIELD_ERROR +let $empty= query_get_value(SELECT bar as foo, baz, 1); +echo $empty is empty; + +--error 0,ER_NO_SUCH_TABLE +if (!`SELECT foo from bar`) { + echo "Yes it's empty"; +} + # ---------------------------------------------------------------------------- # Test comments # ---------------------------------------------------------------------------- From 6e2adc9fb4770f1151f8ce7b7e0353f9c0358fc9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:26:53 +0200 Subject: [PATCH 094/143] Bug #12912120 MTR SHOULD EXPORT MYSQLD'S PATH TO TEST CASES Export $MYSQLD as full path to executable $MYSQLD_CMD is executable with minimum required args --- mysql-test/mysql-test-run.pl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7661714eb03..148339c3890 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2130,6 +2130,12 @@ sub environment_setup { $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= mysql_fix_arguments(); $ENV{'EXE_MYSQL'}= $exe_mysql; + my $exe_mysqld= find_mysqld($basedir); + $ENV{'MYSQLD'}= $exe_mysqld; + my $extra_opts= join (" ", @opt_extra_mysqld_opt); + $ENV{'MYSQLD_CMD'}= "$exe_mysqld --defaults-group-suffix=.1 ". + "--defaults-file=$path_config_file $extra_opts"; + # ---------------------------------------------------- # bug25714 executable may _not_ exist in # some versions, test using it should be skipped From 69e76a168b9311f79f4f5ab6b942bf6048a7241f Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:32:19 +0200 Subject: [PATCH 095/143] Bug #12939555 MTR FINDS ALREADY COMPRESSED CORE WHEN LOOKING FOR CORE FILES AFTER RETRIED TEST Just check that core file name does not end in .gz Not a problem for Windows, as we check for files *ending* in .dmp --- mysql-test/mysql-test-run.pl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 451b877f9a8..1e46ac79d95 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -653,8 +653,9 @@ sub run_test_server ($$$) { my $core_file= $File::Find::name; my $core_name= basename($core_file); - if ($core_name =~ /^core/ or # Starting with core - (IS_WINDOWS and $core_name =~ /\.dmp$/)){ + # Name beginning with core, not ending in .gz + if (($core_name =~ /^core/ and $core_name !~ /\.gz$/) + or (IS_WINDOWS and $core_name =~ /\.dmp$/)){ # Ending with .dmp mtr_report(" - found '$core_name'", "($num_saved_cores/$opt_max_save_core)"); From 93f2daf3ad75562a6a173a032668a6e0556684b5 Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Wed, 14 Sep 2011 16:10:18 +0200 Subject: [PATCH 096/143] Bug#12897501 REPLICATION DOES NOT SUPPORT WINDOWS AUTH PLUG-IN Connection of slave to master using a replication account which authenticates with an external plugin was not possible. Fixed by making sure that the CLIENT_PLUGIN_AUTH capability is set when client connects using mysql_real_connect(). Also, a plugin-dir path used by client library to locate authentication plugins is set based on the analogous server setting. This is done in connect_to_master() function before a call to mysql_real_connect(). --- libmysql/client_settings.h | 5 +++ mysql-test/r/auth_rpl.result | 22 +++++++++++ mysql-test/t/auth_rpl-master.opt | 2 + mysql-test/t/auth_rpl-slave.opt | 4 ++ mysql-test/t/auth_rpl.test | 64 ++++++++++++++++++++++++++++++++ sql/client_settings.h | 15 ++++++-- sql/slave.cc | 4 ++ 7 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/auth_rpl.result create mode 100644 mysql-test/t/auth_rpl-master.opt create mode 100644 mysql-test/t/auth_rpl-slave.opt create mode 100644 mysql-test/t/auth_rpl.test diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index d04d61067f2..ecc9a7773ca 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -22,6 +22,11 @@ extern uint mysql_port; extern char * mysql_unix_port; +/* + Note: CLIENT_CAPABILITIES is also defined in sql/client_settings.h. + When adding capabilities here, consider if they should be also added to + the server's version. +*/ #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \ CLIENT_LONG_FLAG | \ CLIENT_TRANSACTIONS | \ diff --git a/mysql-test/r/auth_rpl.result b/mysql-test/r/auth_rpl.result new file mode 100644 index 00000000000..1c03461df9b --- /dev/null +++ b/mysql-test/r/auth_rpl.result @@ -0,0 +1,22 @@ +include/master-slave.inc +[connection master] +[connection slave] +include/stop_slave.inc +[connection master] +CREATE USER 'plug_user' IDENTIFIED WITH 'test_plugin_server' AS 'plug_user'; +GRANT REPLICATION SLAVE ON *.* TO plug_user; +FLUSH PRIVILEGES; +[connection slave] +CHANGE MASTER TO MASTER_USER= 'plug_user'; +include/start_slave.inc +# Slave in-sync with master now. +SELECT user, plugin, authentication_string FROM mysql.user WHERE user LIKE 'plug_user'; +user plugin authentication_string +plug_user test_plugin_server plug_user +# Cleanup (on slave). +include/stop_slave.inc +CHANGE MASTER TO MASTER_USER='root'; +DROP USER 'plug_user'; +# Cleanup (on master). +DROP USER 'plug_user'; +include/rpl_end.inc diff --git a/mysql-test/t/auth_rpl-master.opt b/mysql-test/t/auth_rpl-master.opt new file mode 100644 index 00000000000..3536d102387 --- /dev/null +++ b/mysql-test/t/auth_rpl-master.opt @@ -0,0 +1,2 @@ +$PLUGIN_AUTH_OPT +$PLUGIN_AUTH_LOAD diff --git a/mysql-test/t/auth_rpl-slave.opt b/mysql-test/t/auth_rpl-slave.opt new file mode 100644 index 00000000000..3f4af6e59bb --- /dev/null +++ b/mysql-test/t/auth_rpl-slave.opt @@ -0,0 +1,4 @@ +--master-retry-count=1 +$PLUGIN_AUTH_OPT +$PLUGIN_AUTH_LOAD + diff --git a/mysql-test/t/auth_rpl.test b/mysql-test/t/auth_rpl.test new file mode 100644 index 00000000000..9947d463acd --- /dev/null +++ b/mysql-test/t/auth_rpl.test @@ -0,0 +1,64 @@ +--source include/have_plugin_auth.inc +--source include/not_embedded.inc +--source include/master-slave.inc + +# +# Check that replication slave can connect to master using an account +# which authenticates with an external authentication plugin (bug#12897501). + +# +# First stop the slave to guarantee that nothing is replicated. +# +--connection slave +--echo [connection slave] +--source include/stop_slave.inc +# +# Create an replication account on the master. +# +--connection master +--echo [connection master] +CREATE USER 'plug_user' IDENTIFIED WITH 'test_plugin_server' AS 'plug_user'; +GRANT REPLICATION SLAVE ON *.* TO plug_user; +FLUSH PRIVILEGES; + +# +# Now go to slave and change the replication user. +# +--connection slave +--echo [connection slave] +--let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1) +CHANGE MASTER TO MASTER_USER= 'plug_user'; + +# +# Start slave with new replication account - this should trigger connection +# to the master server. +# +--source include/start_slave.inc + +# Replicate all statements executed on master, in this case, +# (creation of the plug_user account). +# +--connection master +--sync_slave_with_master +--echo # Slave in-sync with master now. + +SELECT user, plugin, authentication_string FROM mysql.user WHERE user LIKE 'plug_user'; + +# +# Now we can stop the slave and clean up. +# +# Note: it is important that slave is stopped at this +# moment - otherwise master's cleanup statements +# would be replicated on slave! +# +--echo # Cleanup (on slave). +--source include/stop_slave.inc +eval CHANGE MASTER TO MASTER_USER='$master_user'; +DROP USER 'plug_user'; + +--echo # Cleanup (on master). +--connection master +DROP USER 'plug_user'; + +--let $rpl_only_running_threads= 1 +--source include/rpl_end.inc diff --git a/sql/client_settings.h b/sql/client_settings.h index d9145bcce26..acae7907aa5 100644 --- a/sql/client_settings.h +++ b/sql/client_settings.h @@ -23,9 +23,18 @@ #include #include -#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \ - CLIENT_SECURE_CONNECTION | CLIENT_TRANSACTIONS | \ - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION) +/* + Note: CLIENT_CAPABILITIES is also defined in libmysql/client_settings.h. + When adding capabilities here, consider if they should be also added to + the libmysql version. +*/ +#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \ + CLIENT_LONG_FLAG | \ + CLIENT_SECURE_CONNECTION | \ + CLIENT_TRANSACTIONS | \ + CLIENT_PROTOCOL_41 | \ + CLIENT_SECURE_CONNECTION | \ + CLIENT_PLUGIN_AUTH) #define read_user_name(A) {} #undef HAVE_SMEM diff --git a/sql/slave.cc b/sql/slave.cc index d0b123c5c6f..7a3eee952c3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4204,6 +4204,10 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, /* This one is not strictly needed but we have it here for completeness */ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); + /* Set MYSQL_PLUGIN_DIR in case master asks for an external authentication plugin */ + if (opt_plugin_dir_ptr && *opt_plugin_dir_ptr) + mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir_ptr); + while (!(slave_was_killed = io_slave_killed(thd,mi)) && (reconnect ? mysql_reconnect(mysql) != 0 : mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, From 32e8085de932a60d933b6405cdbaf5982d6204c3 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 15 Sep 2011 10:53:19 +0200 Subject: [PATCH 097/143] Bug #12956584 - MYSQLTEST: --ENABLE_X OR --DISABLE_X APPLYING ONLY TO NEXT COMMAND/STMT Followup fixes for --ps-protocol: 1) Incorrectly set ps_protocol variable instead of ps_protocol_enabled 2) disable_result_log was tested after calling handle_no_error() which would revert a temporary setting. --- client/mysqltest.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 6b1f6645b09..806f35bb85a 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -133,7 +133,7 @@ static struct property prop_list[] = { { &disable_connect_log, 0, 1, 1, "$ENABLED_CONNECT_LOG" }, { &disable_info, 0, 1, 1, "$ENABLED_INFO" }, { &display_metadata, 0, 0, 0, "$ENABLED_METADATA" }, - { &ps_protocol, 0, 0, 0, "$ENABLED_PS_PROTOCOL" }, + { &ps_protocol_enabled, 0, 0, 0, "$ENABLED_PS_PROTOCOL" }, { &disable_query_log, 0, 0, 1, "$ENABLED_QUERY_LOG" }, { &disable_result_log, 0, 0, 1, "$ENABLED_RESULT_LOG" }, { &disable_warnings, 0, 0, 1, "$ENABLED_WARNINGS" } @@ -7531,6 +7531,9 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); + /* Remember disable_result_log since handle_no_error() may reset it */ + my_bool dis_res= disable_result_log; + /* Init a new stmt if it's not already one created for this connection */ @@ -7626,7 +7629,7 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, /* If we got here the statement was both executed and read successfully */ handle_no_error(command); - if (!disable_result_log) + if (!dis_res) { /* Not all statements creates a result set. If there is one we can @@ -8821,7 +8824,7 @@ int main(int argc, char **argv) close_statements(); break; case Q_ENABLE_PS_PROTOCOL: - set_property(command, P_PS, 1); + set_property(command, P_PS, ps_protocol); break; case Q_DISABLE_RECONNECT: set_reconnect(&cur_con->mysql, 0); From e24d8bbf0af4d1312f431cf5274fd0fa38646d9f Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 15 Sep 2011 12:20:43 +0200 Subject: [PATCH 098/143] Test federated_plugin must have ps-protocol off --- mysql-test/suite/federated/federated_plugin.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test index 6e5152df17c..8c465095cfa 100644 --- a/mysql-test/suite/federated/federated_plugin.test +++ b/mysql-test/suite/federated/federated_plugin.test @@ -1,5 +1,8 @@ --source include/have_federated_plugin.inc +# Uninstall will not uninstall if ps has been used +--disable_ps_protocol + connect (master,localhost,root,,test,$MASTER_MYPORT,); connect (slave,localhost,root,,test,$SLAVE_MYPORT,); From e0a9cd56a76d4dfcf797e5a0186f53405f0b7fef Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 15 Sep 2011 12:34:32 +0200 Subject: [PATCH 099/143] Bug #11751927 42960: MTR2: NO MORE --STRESS PARAMETERS Quick fix: run mysql-stress-test.pl via a wrapper test Amend mtr to run just that test when using --stress Updated mysql-stress-test.pl to exit(1) if wrong options --- mysql-test/mysql-stress-test.pl | 7 ++++--- mysql-test/mysql-test-run.pl | 25 ++++++++++++++++++++-- mysql-test/suite/stress/t/wrapper.test | 29 ++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/stress/t/wrapper.test diff --git a/mysql-test/mysql-stress-test.pl b/mysql-test/mysql-stress-test.pl index f2471d169d1..0e3b52d7bf5 100755 --- a/mysql-test/mysql-stress-test.pl +++ b/mysql-test/mysql-stress-test.pl @@ -238,9 +238,9 @@ GetOptions("server-host=s", "server-logs-dir=s", "server-port=s", "test-duration=i", "test-suffix=s", "check-tests-file", "verbose", "log-error-details", "cleanup", "mysqltest=s", # OBN: (changing 'abort-on-error' to numberic for WL-4626/4685) - "abort-on-error=i" => \$opt_abort_on_error, "help") || usage(); + "abort-on-error=i" => \$opt_abort_on_error, "help") || usage(1); -usage() if ($opt_help); +usage(0) if ($opt_help); #$opt_abort_on_error=1; @@ -1131,6 +1131,7 @@ sub sig_TERM_handler sub usage { + my $retcode= shift; print < 1 && $opt_start_exit) { - mtr_warning("Parallel and --start-and-exit cannot be combined\n" . + if ($opt_parallel > 1 && ($opt_start_exit || $opt_stress)) { + mtr_warning("Parallel cannot be used with --start-and-exit or --stress\n" . "Setting parallel to 1"); $opt_parallel= 1; } @@ -1174,6 +1176,7 @@ sub command_line_setup { 'report-times' => \$opt_report_times, 'result-file' => \$opt_resfile, 'unit-tests!' => \$opt_ctest, + 'stress=s' => \$opt_stress, 'help|h' => \$opt_usage, # list-options is internal, not listed in help @@ -1627,6 +1630,22 @@ sub command_line_setup { mtr_error("--wait-all can only be used with --start options"); } + # -------------------------------------------------------------------------- + # Gather stress-test options and modify behavior + # -------------------------------------------------------------------------- + + if ($opt_stress) + { + $opt_stress=~ s/,/ /g; + $opt_user_args= 1; + mtr_error("--stress cannot be combined with named ordinary suites or tests") + if $opt_suites || @opt_cases; + $opt_suites="stress"; + @opt_cases= ("wrapper"); + $ENV{MST_OPTIONS}= $opt_stress; + $opt_ctest= 0; + } + # -------------------------------------------------------------------------- # Check timeout arguments # -------------------------------------------------------------------------- @@ -6128,6 +6147,8 @@ Misc options nounit-tests Do not run unit tests. Normally run if configured and if not running named tests/suites unit-tests Run unit tests even if they would otherwise not be run + stress=ARGS Run stress test, providing options to + mysql-stress-test.pl. Options are separated by comma. Some options that control enabling a feature for normal test runs, can be turned off by prepending 'no' to the option, e.g. --notimer. diff --git a/mysql-test/suite/stress/t/wrapper.test b/mysql-test/suite/stress/t/wrapper.test new file mode 100644 index 00000000000..4d2dd808a4c --- /dev/null +++ b/mysql-test/suite/stress/t/wrapper.test @@ -0,0 +1,29 @@ +# +# This is a wrapper "pseudo" test for mtr --stress execution. +# It should not be run directly (will be skipped) +# Do not create a result file! +# + +if (!$MST_OPTIONS) { + skip Only to be run with mtr --stress; +} + +# echo Running MST with options $MST_OPTIONS; + +perl; + my ($mtest)= split " ", $ENV{MYSQL_TEST}; + open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/mtest.inc") or die; + print FILE "let \$MYSQLTEST_BIN= $mtest;\n"; + close FILE; +EOF + +--source $MYSQL_TMP_DIR/mtest.inc +--remove_file $MYSQL_TMP_DIR/mtest.inc + +exec perl mysql-stress-test.pl --mysqltest=$MYSQLTEST_BIN + --server-port=$MASTER_MYPORT --server-socket=$MASTER_MYSOCK + --server-user=root --cleanup + --server-logs-dir=$MYSQLTEST_VARDIR/log + --stress-basedir=$MYSQLTEST_VARDIR + $MST_OPTIONS +; From 4f7a290e70eaf1bdb7bb4c017dfb1cd490f2e917 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 15 Sep 2011 13:18:12 +0200 Subject: [PATCH 100/143] Some tests simplified after 12912120 --- mysql-test/t/mysql_plugin.test | 1 - mysql-test/t/mysqld--defaults-file.test | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/mysql-test/t/mysql_plugin.test b/mysql-test/t/mysql_plugin.test index b07ce40e43a..2ad9a8de186 100644 --- a/mysql-test/t/mysql_plugin.test +++ b/mysql-test/t/mysql_plugin.test @@ -45,7 +45,6 @@ use File::Basename; my $plugindir_ini= "$ENV{PLUGIN_DIR}/daemon_example.ini"; my $notfound= ""; open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/mysqld.inc") or die; - print FILE "let \$MYSQLD= $mysqld;\n"; print FILE "let \$MYSQLD_BASEDIR= $mysqld_basedir;\n"; print FILE "let \$MYSQL_MY_PRINT_DEFAULTS_BASEDIR= $my_print_defaults_basedir;\n"; if ((!-e $daemonexample_ini) || (!-r $daemonexample_ini)) diff --git a/mysql-test/t/mysqld--defaults-file.test b/mysql-test/t/mysqld--defaults-file.test index 065436c38aa..3bfe0aa891f 100644 --- a/mysql-test/t/mysqld--defaults-file.test +++ b/mysql-test/t/mysqld--defaults-file.test @@ -5,21 +5,6 @@ source include/not_embedded.inc; source include/not_windows.inc; -# We need to use a plain "mysqld" without any other options to trigger -# the bug. In particular, it seems that passing --bootstrap does not -# trigger the bug. To do that, we extract the "command name" from the -# MYSQLD_BOOTSTRAP_CMD variable and store that in a file, which we -# then load into the test case. - -perl; - my ($mysqld)= split " ", $ENV{MYSQLD_BOOTSTRAP_CMD}; - open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/mysqld.inc") or die; - print FILE "let \$MYSQLD= $mysqld;\n"; - close FILE; -EOF - -source $MYSQL_TMP_DIR/mysqld.inc; - # All these tests refer to configuration files that do not exist --error 1 @@ -44,4 +29,3 @@ exec $MYSQLD --defaults-file=with.ext --print-defaults 2>&1; --error 1 exec $MYSQLD --defaults-file=no_extension --print-defaults 2>&1; -remove_file $MYSQL_TMP_DIR/mysqld.inc; From 3f9cbd7731fa268575242095cd29d00be2a222f2 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 16 Sep 2011 15:30:31 +0400 Subject: [PATCH 101/143] 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: A test case for BUG#11761180. mysql-test/t/myisampack.test: A test case for BUG#11761180. storage/myisam/ft_boolean_search.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/ft_nlq_search.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/mi_check.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/mi_write.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. --- 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 c388e9c49dd96b46c06033dbc476b42e75291f7f Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Fri, 16 Sep 2011 14:35:25 +0200 Subject: [PATCH 102/143] Update of auth_rpl test. For some reason the test authentication plugin accepted connection with arbitrary password. But the intention of the plugin is that password should equal to the authentication string and in the later versions of the server connection fails if password is wrong. So I have updated auth_rpl test to specify the correct password. --- mysql-test/r/auth_rpl.result | 4 +++- mysql-test/t/auth_rpl.test | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/auth_rpl.result b/mysql-test/r/auth_rpl.result index 1c03461df9b..70626b02b2b 100644 --- a/mysql-test/r/auth_rpl.result +++ b/mysql-test/r/auth_rpl.result @@ -7,7 +7,9 @@ CREATE USER 'plug_user' IDENTIFIED WITH 'test_plugin_server' AS 'plug_user'; GRANT REPLICATION SLAVE ON *.* TO plug_user; FLUSH PRIVILEGES; [connection slave] -CHANGE MASTER TO MASTER_USER= 'plug_user'; +CHANGE MASTER TO +MASTER_USER= 'plug_user', +MASTER_PASSWORD= 'plug_user'; include/start_slave.inc # Slave in-sync with master now. SELECT user, plugin, authentication_string FROM mysql.user WHERE user LIKE 'plug_user'; diff --git a/mysql-test/t/auth_rpl.test b/mysql-test/t/auth_rpl.test index 9947d463acd..c413a84b53c 100644 --- a/mysql-test/t/auth_rpl.test +++ b/mysql-test/t/auth_rpl.test @@ -27,7 +27,9 @@ FLUSH PRIVILEGES; --connection slave --echo [connection slave] --let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1) -CHANGE MASTER TO MASTER_USER= 'plug_user'; +CHANGE MASTER TO + MASTER_USER= 'plug_user', + MASTER_PASSWORD= 'plug_user'; # # Start slave with new replication account - this should trigger connection From 4896fc11b70274f903b89e329464bea122991192 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 19 Sep 2011 16:06:35 +0200 Subject: [PATCH 103/143] Bug #12916194 MTR SHOULD CUT OFF ANALYSIS OF SERVER LOG IF THERE IS TOO MUCH Added simple cut-off w/warning if > one million lines --- mysql-test/mysql-test-run.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 148339c3890..4e4333767da 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3855,6 +3855,11 @@ sub extract_server_log ($$) { else { push(@lines, $line); + if (scalar(@lines) > 1000000) { + $Ferr = undef; + mtr_warning("Too much log from test, bailing out from extracting"); + return (); + } } } else From 4d19a19d6e19d76d18fccd7e863ec8211a9de110 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 19 Sep 2011 16:08:52 +0200 Subject: [PATCH 104/143] Bug #12934729 MTR: ADD OPTION TO RUN BOOTSTRAP THROUGH DEBUGGER Added options --boot-gdb etc. Extended gdb_arguments() with optional input argument Cannot use set args in gdb init file, as run < kills them (?) --- mysql-test/mysql-test-run.pl | 45 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 401b3ab2b5a..288aa2dfda2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -224,10 +224,13 @@ our %gprof_dirs; our $glob_debugger= 0; our $opt_gdb; our $opt_client_gdb; +my $opt_boot_gdb; our $opt_dbx; our $opt_client_dbx; +my $opt_boot_dbx; our $opt_ddd; our $opt_client_ddd; +my $opt_boot_ddd; our $opt_manual_gdb; our $opt_manual_dbx; our $opt_manual_ddd; @@ -1100,14 +1103,17 @@ sub command_line_setup { 'gdb' => \$opt_gdb, 'client-gdb' => \$opt_client_gdb, 'manual-gdb' => \$opt_manual_gdb, + 'boot-gdb' => \$opt_boot_gdb, 'manual-debug' => \$opt_manual_debug, 'ddd' => \$opt_ddd, 'client-ddd' => \$opt_client_ddd, 'manual-ddd' => \$opt_manual_ddd, + 'boot-ddd' => \$opt_boot_ddd, 'dbx' => \$opt_dbx, 'client-dbx' => \$opt_client_dbx, 'manual-dbx' => \$opt_manual_dbx, 'debugger=s' => \$opt_debugger, + 'boot-dbx' => \$opt_boot_dbx, 'client-debugger=s' => \$opt_client_debugger, 'strace-client:s' => \$opt_strace_client, 'max-save-core=i' => \$opt_max_save_core, @@ -3259,6 +3265,19 @@ sub mysql_install_db { # ---------------------------------------------------------------------- my $bootstrap_sql_file= "$opt_vardir/tmp/bootstrap.sql"; + if ($opt_boot_gdb) { + gdb_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(), + $bootstrap_sql_file); + } + if ($opt_boot_dbx) { + dbx_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(), + $bootstrap_sql_file); + } + if ($opt_boot_ddd) { + ddd_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(), + $bootstrap_sql_file); + } + my $path_sql= my_find_file($install_basedir, ["mysql", "sql/share", "share/mysql", "share", "scripts"], @@ -5581,19 +5600,21 @@ sub gdb_arguments { my $args= shift; my $exe= shift; my $type= shift; + my $input= shift; - # Write $args to gdb init file - my $str= join " ", map { s/"/\\"/g; "\"$_\""; } @$$args; my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type"; # Remove the old gdbinit file unlink($gdb_init_file); + # Put $args into a single string + my $str= join(" ", @$$args); + my $runline= $input ? "run $str < $input" : "run $str"; + # write init file for mysqld or client mtr_tofile($gdb_init_file, - "set args $str\n" . "break main\n" . - "run"); + $runline); if ( $opt_manual_gdb ) { @@ -5632,20 +5653,22 @@ sub ddd_arguments { my $args= shift; my $exe= shift; my $type= shift; + my $input= shift; - # Write $args to ddd init file - my $str= join " ", map { s/"/\\"/g; "\"$_\""; } @$$args; my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type"; # Remove the old gdbinit file unlink($gdb_init_file); + # Put $args into a single string + my $str= join(" ", @$$args); + my $runline= $input ? "run $str < $input" : "run $str"; + # write init file for mysqld or client mtr_tofile($gdb_init_file, "file $$exe\n" . - "set args $str\n" . "break main\n" . - "run"); + $runline); if ( $opt_manual_ddd ) { @@ -5681,14 +5704,16 @@ sub dbx_arguments { my $args= shift; my $exe= shift; my $type= shift; + my $input= shift; # Put $args into a single string my $str= join " ", @$$args; + my $runline= $input ? "run $str < $input" : "run $str"; if ( $opt_manual_dbx ) { print "\nTo start dbx for $type, type in another window:\n"; print "cd $glob_mysql_test_dir; dbx -c \"stop in main; " . - "run $str\" $$exe\n"; + "$runline\" $$exe\n"; # Indicate the exe should not be started $$exe= undef; @@ -5707,7 +5732,7 @@ sub dbx_arguments { mtr_add_arg($$args, "dbx"); mtr_add_arg($$args, "-c"); - mtr_add_arg($$args, "stop in main; run $str"); + mtr_add_arg($$args, "stop in main; $runline"); mtr_add_arg($$args, "$$exe"); $$exe= "xterm"; From 3ad46f8111ac049c64ab3a9703c5c3f148aab162 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Mon, 19 Sep 2011 21:16:01 +0200 Subject: [PATCH 105/143] Don't use macro names in changelog comments. --- support-files/mysql.spec.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 19595f228ef..8ce97ec4974 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1154,9 +1154,9 @@ echo "=====" >> $STATUS_HISTORY * Tue Sep 13 2011 Jonathan Perkin - Add support for Oracle Linux 6 and Red Hat Enterprise Linux 6. Due to - changes in RPM behaviour ($RPM_BUILD_ROOT is removed prior to %install) - this necessitated a move of the libmygcc.a installation from %build to - %install, which is probably where it belonged in the first place. + changes in RPM behaviour ($RPM_BUILD_ROOT is removed prior to install) + this necessitated a move of the libmygcc.a installation to the install + phase, which is probably where it belonged in the first place. * Tue Sep 13 2011 Joerg Bruehe From dbcdad7d4a726a28aa0a210a674ec26d1ac5c98e Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 20 Sep 2011 10:59:48 +0200 Subject: [PATCH 106/143] Bug#12985030 SIMPLE QUERY WITH DECIMAL NUMBERS LEAKS MEMORY mysql-test/r/func_str.result: New test cases. mysql-test/t/func_str.test: New test cases. strings/dtoa.c: Increasing the buffer size slightly made some queries pass without leaks. Adding Bfree(p51, alloc) fixed the remaining leaks. --- mysql-test/r/func_str.result | 35 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 19 +++++++++++++++++++ strings/dtoa.c | 7 +++++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 81fe2413725..755763e6994 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2785,5 +2785,40 @@ format(123,2,'no_NO') 123,00 DROP TABLE t1; # +# Bug#12985030 SIMPLE QUERY WITH DECIMAL NUMBERS LEAKS MEMORY +# +SELECT (rpad(1.0,2048,1)) IS NOT FALSE; +(rpad(1.0,2048,1)) IS NOT FALSE +1 +SELECT ((+0) IN +((0b111111111111111111111111111111111111111111111111111),(rpad(1.0,2048,1)), +(32767.1))); +((+0) IN +((0b111111111111111111111111111111111111111111111111111),(rpad(1.0,2048,1)), +(32767.1))) +0 +SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)); +((rpad(1.0,2048,1)) = ('4(') ^ (0.1)) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '4(' +SELECT +pow((rpad(1.0,2048,1)),(b'1111111111111111111111111111111111111111111')); +ERROR 22003: DOUBLE value is out of range in 'pow(rpad(1.0,2048,1),0x07ffffffffff)' +SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../')); +((rpad(1.0,2048,1)) + (0) ^ ('../')) +1.011111111111111 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '../' +SELECT stddev_samp(rpad(1.0,2048,1)); +stddev_samp(rpad(1.0,2048,1)) +NULL +SELECT ((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1))); +((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1))) +1 +SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc)); +((0xf3) * (rpad(1.0,2048,1)) << (0xcc)) +0 +# # End of 5.5 tests # diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9a9a8110a74..2a14648d6f6 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1436,6 +1436,25 @@ SHOW CREATE TABLE t1; SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # Bug#12985030 SIMPLE QUERY WITH DECIMAL NUMBERS LEAKS MEMORY +--echo # + +SELECT (rpad(1.0,2048,1)) IS NOT FALSE; +SELECT ((+0) IN +((0b111111111111111111111111111111111111111111111111111),(rpad(1.0,2048,1)), +(32767.1))); +SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)); + +--error 1690 +SELECT +pow((rpad(1.0,2048,1)),(b'1111111111111111111111111111111111111111111')); +SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../')); +SELECT stddev_samp(rpad(1.0,2048,1)); +SELECT ((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1))); +SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc)); + + --echo # --echo # End of 5.5 tests --echo # diff --git a/strings/dtoa.c b/strings/dtoa.c index e4eb10bb6f8..05c9bb6e529 100644 --- a/strings/dtoa.c +++ b/strings/dtoa.c @@ -46,7 +46,7 @@ see if it is possible to get rid of malloc(). this constant is sufficient to avoid malloc() on all inputs I have tried. */ -#define DTOA_BUFF_SIZE (420 * sizeof(void *)) +#define DTOA_BUFF_SIZE (460 * sizeof(void *)) /* Magic value returned by dtoa() to indicate overflow */ #define DTOA_OVERFLOW 9999 @@ -659,6 +659,7 @@ typedef struct Stack_alloc static Bigint *Balloc(int k, Stack_alloc *alloc) { Bigint *rv; + DBUG_ASSERT(k <= Kmax); if (k <= Kmax && alloc->freelist[k]) { rv= alloc->freelist[k]; @@ -1005,7 +1006,7 @@ static Bigint p5_a[]= static Bigint *pow5mult(Bigint *b, int k, Stack_alloc *alloc) { - Bigint *b1, *p5, *p51; + Bigint *b1, *p5, *p51=NULL; int i; static int p05[3]= { 5, 25, 125 }; @@ -1037,6 +1038,8 @@ static Bigint *pow5mult(Bigint *b, int k, Stack_alloc *alloc) p5= p51; } } + if (p51) + Bfree(p51, alloc); return b; } From 7841a553ccefa7f1299b902c59ab505172d49957 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 20 Sep 2011 11:48:52 +0100 Subject: [PATCH 107/143] BUG#13001711: UNINITIALIZED VALUE IN MASTER_INFO::CLEAR_IN_MEMORY_INFO WITH MYSQL_REFRESH() reset_slave_info.all was not initialized. We fix this by setting lex->reset_slave_info.all= false in the lex_start routine, which is called before every statement. --- sql/sql_lex.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1cc967c5055..9b2bdf5b5cc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -435,6 +435,7 @@ void lex_start(THD *thd) lex->is_lex_started= TRUE; lex->used_tables= 0; + lex->reset_slave_info.all= false; DBUG_VOID_RETURN; } From 1f9fe1b4d51d268730875039967c847678600700 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Tue, 20 Sep 2011 17:47:53 +0200 Subject: [PATCH 108/143] Update email address for Release Engineering. --- cmake/mysql_version.cmake | 4 ++-- support-files/mysql.spec.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/mysql_version.cmake b/cmake/mysql_version.cmake index 122f0e63736..f21d29815e6 100644 --- a/cmake/mysql_version.cmake +++ b/cmake/mysql_version.cmake @@ -94,8 +94,8 @@ ENDIF() IF(NOT CPACK_SOURCE_PACKAGE_FILE_NAME) SET(CPACK_SOURCE_PACKAGE_FILE_NAME "mysql-${VERSION}") ENDIF() -SET(CPACK_PACKAGE_CONTACT "MySQL Build Team ") -SET(CPACK_PACKAGE_VENDOR "Sun Microsystems, Inc") +SET(CPACK_PACKAGE_CONTACT "MySQL Release Engineering ") +SET(CPACK_PACKAGE_VENDOR "Oracle Corporation") SET(CPACK_SOURCE_GENERATOR "TGZ") INCLUDE(cpack_source_ignore_files) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 8ce97ec4974..cc6cfdbb778 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -247,7 +247,7 @@ Distribution: %{distro_description} License: Copyright (c) 2000, @MYSQL_COPYRIGHT_YEAR@, %{mysql_vendor}. All rights reserved. Under %{license_type} license as shown in the Description field. Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/%{src_dir}.tar.gz URL: http://www.mysql.com/ -Packager: MySQL Build Team +Packager: MySQL Release Engineering Vendor: %{mysql_vendor} Provides: msqlormysql MySQL-server mysql BuildRequires: %{distro_buildreq} From 265737d141d3490497746ac16b625f5883f5856d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2011 18:12:36 -0600 Subject: [PATCH 109/143] 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 d27d267ee73e9d307e80d4bf91aefcf746b502f7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2011 18:17:36 -0600 Subject: [PATCH 110/143] 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. --- mysql-test/suite/innodb/r/innodb-index.result | 91 ++++++++++++++++--- mysql-test/suite/innodb/t/innodb-index.test | 84 +++++++++++++---- storage/innobase/row/row0purge.c | 20 ++-- 3 files changed, 153 insertions(+), 42 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index 2e9ee652a76..a33099661aa 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/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; @@ -961,20 +1036,6 @@ ERROR HY000: Too big row alter table t1 row_format=compact; create index t1u on t1 (u(767)); 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(767)), INDEX(b(767)) @@ -1155,3 +1216,5 @@ SELECT SLEEP(10); SLEEP(10) 0 DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; +DROP TABLE t12637786; +DROP TABLE t12963823; diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test index 1df65afe94c..d52237e02e3 100644 --- a/mysql-test/suite/innodb/t/innodb-index.test +++ b/mysql-test/suite/innodb/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; @@ -459,24 +521,6 @@ create index t1u on t1 (u(767)); 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, @@ -636,6 +680,8 @@ DROP TABLE t1; #this delay is needed because 45225_2 is disabled, to allow the purge to run SELECT SLEEP(10); 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/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index c008c2d1c31..e23995b8a52 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2010, 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 *****************************************************************************/ @@ -515,7 +515,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; } @@ -645,14 +646,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)) { @@ -665,7 +666,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 */ @@ -715,7 +717,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 8e56eb58ec16df6320f514f93deaba1c6c4d006f Mon Sep 17 00:00:00 2001 From: Daniel Fischer Date: Wed, 21 Sep 2011 12:43:02 +0200 Subject: [PATCH 111/143] post-merge fix --- .bzr-mysql/default.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index 1b6d7676984..43d479a1043 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] -post_commit_to = "dbg_mysql_security@sun.com" -post_push_to = "dbg_mysql_security@sun.com" -tree_name = "mysql-5.5-security" +post_commit_to = "commits@lists.mysql.com" +post_push_to = "commits@lists.mysql.com" +tree_name = "mysql-5.5" From f9b064a406a9836cac109c5dcdd9354cbb4303b7 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Wed, 21 Sep 2011 13:46:49 +0200 Subject: [PATCH 112/143] Bug#12985030 SIMPLE QUERY WITH DECIMAL NUMBERS LEAKS MEMORY Extra fix: 'if (p5 < p5_a + P5A_MAX)' is not portable. p5 starts out pointing to a static array, then may point to a buffer on the stack, then may point to malloc()ed memory. --- strings/dtoa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/strings/dtoa.c b/strings/dtoa.c index 05c9bb6e529..f7c38b2420d 100644 --- a/strings/dtoa.c +++ b/strings/dtoa.c @@ -1009,6 +1009,7 @@ static Bigint *pow5mult(Bigint *b, int k, Stack_alloc *alloc) Bigint *b1, *p5, *p51=NULL; int i; static int p05[3]= { 5, 25, 125 }; + my_bool overflow= FALSE; if ((i= k & 3)) b= multadd(b, p05[i-1], 0, alloc); @@ -1027,16 +1028,19 @@ static Bigint *pow5mult(Bigint *b, int k, Stack_alloc *alloc) if (!(k>>= 1)) break; /* Calculate next power of 5 */ - if (p5 < p5_a + P5A_MAX) - ++p5; - else if (p5 == p5_a + P5A_MAX) - p5= mult(p5, p5, alloc); - else + if (overflow) { p51= mult(p5, p5, alloc); Bfree(p5, alloc); p5= p51; } + else if (p5 < p5_a + P5A_MAX) + ++p5; + else if (p5 == p5_a + P5A_MAX) + { + p5= mult(p5, p5, alloc); + overflow= TRUE; + } } if (p51) Bfree(p51, alloc); From 7f729cfac492ecc6e581f2d07c41a49726fa2e04 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 113/143] 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; } From 9fb56539d055375b5881ded8d31131af5a81816c Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 26 Sep 2011 10:47:08 +0200 Subject: [PATCH 114/143] Fixed test sys_vars.all_vars: innodb_large_prefix no longer missing --- mysql-test/suite/sys_vars/r/all_vars.result | 2 -- 1 file changed, 2 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 715ad9e2c15..af05e3bc393 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,7 +11,5 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: -INNODB_LARGE_PREFIX -INNODB_LARGE_PREFIX drop table t1; drop table t2; From 0b706e54bb321cbf88571b03a6fc64c3fecc3d84 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 26 Sep 2011 14:21:28 +0200 Subject: [PATCH 115/143] Bug#12985030 SIMPLE QUERY WITH DECIMAL NUMBERS LEAKS MEMORY Re-write the test, to make pushbuild green. Workaraound for broken pow() function on: SunOS tyr40 5.10 Generic_127112-05 i86pc i386 i86pc (dbx) where current thread: t@1 =>[1] Item_func_pow::val_real(this = 0x238af20) (optimized), at 0xaa8d13 (line ~1980) in "item_func.cc" (dbx) print pow(1.01, 1.0) pow(1.01, 1) = 1.01 (dbx) print pow(1.01, 10.0) pow(1.01, 10) = 1.1046221254112 (dbx) print pow(1.01, 100.0) pow(1.01, 100) = 2.7048138294215 (dbx) print pow(1.01, 1000.0) pow(1.01, 1000) = 20959.155637814 (dbx) print pow(1.01, 10000.0) pow(1.01, 10000) = 1.635828711189e+43 (dbx) print pow(1.01, 100000.0) pow(1.01, 100000) = Infinity (dbx) print pow(1.01, 1000000.0) pow(1.01, 1000000) = Infinity (dbx) print pow(1.01, 10000000.0) pow(1.01, 10000000) = Infinity (dbx) print pow(1.01, 100000000.0) pow(1.01, 100000000) = Infinity (dbx) print pow(1.01, 1000000000.0) pow(1.01, 1000000000) = 0.0 (dbx) print pow(1.01, 10000000000.0) pow(1.01, 10000000000) = 0.0 (dbx) print value value = 1.0111111111111 (dbx) print val2 val2 = 8796093022207.0 (dbx) print pow(value, val2) pow(value, val2) = 0.0 so it seems pow(1.01, y) returns Infinity for large y, but then starts to return 0.0 for even larger values of y. --- mysql-test/r/func_str.result | 4 ++-- mysql-test/t/func_str.test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 755763e6994..5d3ac26fe3d 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2803,8 +2803,8 @@ SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)); Warnings: Warning 1292 Truncated incorrect INTEGER value: '4(' SELECT -pow((rpad(1.0,2048,1)),(b'1111111111111111111111111111111111111111111')); -ERROR 22003: DOUBLE value is out of range in 'pow(rpad(1.0,2048,1),0x07ffffffffff)' +pow((rpad(10.0,2048,1)),(b'1111111111111111111111111111111111111111111')); +ERROR 22003: DOUBLE value is out of range in 'pow(rpad(10.0,2048,1),0x07ffffffffff)' SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../')); ((rpad(1.0,2048,1)) + (0) ^ ('../')) 1.011111111111111 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 2a14648d6f6..bb22366a98d 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1448,7 +1448,7 @@ SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1)); --error 1690 SELECT -pow((rpad(1.0,2048,1)),(b'1111111111111111111111111111111111111111111')); +pow((rpad(10.0,2048,1)),(b'1111111111111111111111111111111111111111111')); SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../')); SELECT stddev_samp(rpad(1.0,2048,1)); SELECT ((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1))); From da756ef676100c3257a07394106d6c573ddc0225 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 27 Sep 2011 12:56:05 +0200 Subject: [PATCH 116/143] Bug #12844282 62075: MTR TESTS SHOULD NOT HAVE TO SAVE & RESET INNODB_FILE_FORMAT_CHECK Added 'innodb_file_format_check' as variable to ignore change to. Tests that had to restore this amended Two tests assumed it to be Antelope, make sure these run on a freshly started server For 5.5, apparently innodb_file_format_max is the one to ignore --- mysql-test/include/mtr_check.sql | 3 ++- mysql-test/r/partition_innodb_plugin.result | 2 -- mysql-test/suite/innodb_plugin/r/innodb_bug52745.result | 1 - mysql-test/suite/innodb_plugin/r/innodb_bug53591.result | 1 - .../suite/innodb_plugin/t/innodb-autoinc-18274.test | 9 --------- .../suite/innodb_plugin/t/innodb-autoinc-44030.test | 9 --------- .../suite/innodb_plugin/t/innodb-autoinc-56228.test | 9 --------- mysql-test/suite/innodb_plugin/t/innodb-autoinc.test | 9 --------- .../suite/innodb_plugin/t/innodb-create-options.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb-index.test | 9 --------- mysql-test/suite/innodb_plugin/t/innodb-zip.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug36172.test | 2 -- .../suite/innodb_plugin/t/innodb_bug47167-master.opt | 1 + mysql-test/suite/innodb_plugin/t/innodb_bug52745.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug53591.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug56680.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug59641.test | 4 ---- .../suite/innodb_plugin/t/innodb_file_format-master.opt | 1 + mysql-test/t/partition_innodb_plugin.test | 2 -- 19 files changed, 4 insertions(+), 68 deletions(-) create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index 699a35a1831..64bb7c01544 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -27,7 +27,8 @@ BEGIN -- Dump all global variables except those -- that are supposed to change SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES - WHERE variable_name != 'timestamp' ORDER BY VARIABLE_NAME; + WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_check') + ORDER BY VARIABLE_NAME; -- Dump all databases, there should be none -- except those that was created during bootstrap diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result index f6b5ce84338..43838170501 100644 --- a/mysql-test/r/partition_innodb_plugin.result +++ b/mysql-test/r/partition_innodb_plugin.result @@ -2,7 +2,6 @@ call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB # # Bug#55091: Server crashes on ADD PARTITION after a failed attempt # -SET @old_innodb_file_format_check = @@global.innodb_file_format_check; SET @old_innodb_file_format = @@global.innodb_file_format; SET @old_innodb_file_per_table = @@global.innodb_file_per_table; SET @old_innodb_strict_mode = @@global.innodb_strict_mode; @@ -70,7 +69,6 @@ DROP TABLE t1; SET @@global.innodb_strict_mode = @old_innodb_strict_mode; SET @@global.innodb_file_format = @old_innodb_file_format; SET @@global.innodb_file_per_table = @old_innodb_file_per_table; -SET @@global.innodb_file_format_check = @old_innodb_file_format_check; SET NAMES utf8; CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) ENGINE=InnoDB diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result index 254c6525257..74db8b0c20a 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result @@ -126,5 +126,4 @@ Warning 1265 Data truncated for column 'col79' at row 1 Warning 1264 Out of range value for column 'col84' at row 1 DROP TABLE bug52745; SET GLOBAL innodb_file_format=Antelope; -SET GLOBAL innodb_file_format_check=Antelope; SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result b/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result index 1f05b6d2a57..29f9d09a71c 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result @@ -12,5 +12,4 @@ Error 1118 Row size too large. The maximum row size for the used table type, not Error 1030 Got error 139 from storage engine DROP TABLE bug53591; SET GLOBAL innodb_file_format=Antelope; -SET GLOBAL innodb_file_format_check=Antelope; SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test index 8734311dd7a..9ac24c9e349 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -20,10 +18,3 @@ SHOW CREATE TABLE t1; INSERT INTO t1 VALUES(null); SELECT * FROM t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test index 99cdac72e2e..150f6bb4f66 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -34,10 +32,3 @@ SHOW CREATE TABLE t1; INSERT INTO t1 VALUES(null); SELECT * FROM t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test index eb38b21861d..41b8ac90fad 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test @@ -1,7 +1,5 @@ -- source include/have_innodb_plugin.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - ## # Bug #56228: dropping tables from within an active statement crashes server # @@ -33,10 +31,3 @@ SELECT bug56228(); DROP FUNCTION bug56228; DROP TEMPORARY TABLE t2_56228; DROP TEMPORARY TABLE IF EXISTS t1_56228; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test index 4967a6efbb9..633b0ef360b 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -639,10 +637,3 @@ INSERT INTO t1 VALUES (18446744073709551615); -- source include/restart_mysqld.inc SHOW CREATE TABLE t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-create-options.test b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test index 2f95ccc45cb..85f214177aa 100755 --- a/mysql-test/suite/innodb_plugin/t/innodb-create-options.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test @@ -61,7 +61,6 @@ SET storage_engine=InnoDB; --disable_query_log # These values can change during the test LET $innodb_file_format_orig=`select @@innodb_file_format`; -LET $innodb_file_format_check_orig=`select @@innodb_file_format_check`; LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`; LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`; --enable_query_log @@ -568,7 +567,6 @@ DROP TABLE IF EXISTS t1; --disable_query_log EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig; -EVAL SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig; EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig; --enable_query_log diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index a671b48a9c1..568661c67f1 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -2,8 +2,6 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - let $per_table=`select @@innodb_file_per_table`; let $format=`select @@innodb_file_format`; set global innodb_file_per_table=on; @@ -680,10 +678,3 @@ DROP TABLE t1; 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 -# - --- disable_query_log -eval SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-zip.test b/mysql-test/suite/innodb_plugin/t/innodb-zip.test index 5ed101b7f20..760ab67ca54 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-zip.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-zip.test @@ -2,7 +2,6 @@ let $per_table=`select @@innodb_file_per_table`; let $format=`select @@innodb_file_format`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; set global innodb_file_per_table=off; set global innodb_file_format=`0`; @@ -337,4 +336,3 @@ drop table normal_table, zip_table; -- disable_query_log eval set global innodb_file_format=$format; eval set global innodb_file_per_table=$per_table; -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test b/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test index fbd6d5605df..85a90f3785d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test @@ -15,7 +15,6 @@ SET storage_engine=InnoDB; -- disable_result_log let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -28,5 +27,4 @@ INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.90 CHECK TABLE table0 EXTENDED; DROP TABLE table0; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test b/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test index b20a993a2d1..c1af389afbd 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test @@ -1,7 +1,6 @@ -- source include/have_innodb_plugin.inc let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -105,5 +104,4 @@ SHOW WARNINGS; DROP TABLE bug52745; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test b/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test index 760b4630383..f32aace83b2 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test @@ -1,7 +1,6 @@ -- source include/have_innodb_plugin.inc let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; @@ -18,5 +17,4 @@ SHOW WARNINGS; DROP TABLE bug53591; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test b/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test index 8d0f685c723..fa8fa39b895 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test @@ -7,7 +7,6 @@ SET @tx_isolation_orig = @@tx_isolation; SET @innodb_file_per_table_orig = @@innodb_file_per_table; SET @innodb_file_format_orig = @@innodb_file_format; -SET @innodb_file_format_check_orig = @@innodb_file_format_check; # The flag innodb_change_buffering_debug is only available in debug builds. # It instructs InnoDB to try to evict pages from the buffer pool when # change buffering is possible, so that the change buffer will be used @@ -137,6 +136,5 @@ DROP TABLE bug56680; SET GLOBAL tx_isolation = @tx_isolation_orig; SET GLOBAL innodb_file_per_table = @innodb_file_per_table_orig; SET GLOBAL innodb_file_format = @innodb_file_format_orig; -SET GLOBAL innodb_file_format_check = @innodb_file_format_check_orig; -- error 0, ER_UNKNOWN_SYSTEM_VARIABLE SET GLOBAL innodb_change_buffering_debug = @innodb_change_buffering_debug_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test index 0fb24e47a54..028c21afe4a 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test @@ -3,8 +3,6 @@ -- source include/not_embedded.inc -- source include/have_innodb_plugin.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; @@ -66,5 +64,3 @@ XA COMMIT '789'; SELECT * FROM t; DROP TABLE t; ---disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test index 626e5d19b99..98504469243 100644 --- a/mysql-test/t/partition_innodb_plugin.test +++ b/mysql-test/t/partition_innodb_plugin.test @@ -9,7 +9,6 @@ call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB --echo # --echo # Bug#55091: Server crashes on ADD PARTITION after a failed attempt --echo # -SET @old_innodb_file_format_check = @@global.innodb_file_format_check; SET @old_innodb_file_format = @@global.innodb_file_format; SET @old_innodb_file_per_table = @@global.innodb_file_per_table; SET @old_innodb_strict_mode = @@global.innodb_strict_mode; @@ -68,7 +67,6 @@ DROP TABLE t1; SET @@global.innodb_strict_mode = @old_innodb_strict_mode; SET @@global.innodb_file_format = @old_innodb_file_format; SET @@global.innodb_file_per_table = @old_innodb_file_per_table; -SET @@global.innodb_file_format_check = @old_innodb_file_format_check; # # Bug#32430 - show engine innodb status causes errors From 5dbcff9b9c86dc9608252d270b6ebff7a6066040 Mon Sep 17 00:00:00 2001 From: Ashish Agarwal Date: Tue, 27 Sep 2011 17:38:51 +0530 Subject: [PATCH 117/143] BUG#11759349 - 51655: CREATE TABLE IN MEMORY ENGINE DOESN'T STORE CREATE_TIME IN INFORMATION_SC It was impossible to determine MEMORY table creation time, since it wasn't stored/exposed. With this patch creation time is saved and it is available via I_S.TABLES.CREATE_TIME. Note: it was decided that additional analysis is required before implementing UPDATE_TIME. Thus this patch doesn't store UPDATE_TIME. --- include/heap.h | 2 ++ mysql-test/r/heap.result | 4 ++-- mysql-test/r/show_check.result | 44 +++++++++++++++++----------------- mysql-test/t/heap.test | 2 +- mysql-test/t/show_check.test | 20 ++++++++-------- storage/heap/ha_heap.cc | 1 + storage/heap/hp_create.c | 1 + storage/heap/hp_info.c | 1 + 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/include/heap.h b/include/heap.h index 0abdd71461e..7adaac33096 100644 --- a/include/heap.h +++ b/include/heap.h @@ -50,6 +50,7 @@ typedef struct st_heapinfo /* Struct from heap_info */ uint reclength; /* Length of one record */ int errkey; ulonglong auto_increment; + time_t create_time; } HEAPINFO; @@ -146,6 +147,7 @@ typedef struct st_heap_share uint open_count; uchar *del_link; /* Link to next block with del. rec */ char * name; /* Name of "memory-file" */ + time_t create_time; #ifdef THREAD THR_LOCK lock; pthread_mutex_t intern_lock; /* Locking for use with _locking */ diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index ddf675e2f73..fd072bbab5d 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -715,8 +715,8 @@ create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; show table status like 't_'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL # NULL NULL latin1_swedish_ci NULL drop table t1, t2; CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 7cb3f696449..7b633d42f44 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -458,57 +458,57 @@ insert into t2 values (1),(2); insert into t3 values (1,1),(2,2); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (3),(4); insert into t2 values (3),(4); insert into t3 values (3,3),(4,4); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL delete from t1 where a=3; delete from t2 where b=3; delete from t3 where a=3; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL truncate table t1; truncate table t2; truncate table t3; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL delete from t1 where a=5; delete from t2 where b=5; delete from t3 where a=5; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL drop table t1, t2, t3; create database mysqltest; show create database mysqltest; @@ -659,7 +659,7 @@ DROP TABLE t1; flush tables; SHOW TABLE STATUS like 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 NULL NULL NULL NULL # # # # NULL NULL NULL NULL NULL NULL NULL NULL Incorrect information in file: './test/t1.frm' +t1 NULL NULL NULL NULL # # # # NULL NULL # NULL NULL NULL NULL NULL Incorrect information in file: './test/t1.frm' Warnings: Warning 1033 Incorrect information in file: './test/t1.frm' show create table t1; diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 3f91b9966e7..1e69b43d79b 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -454,7 +454,7 @@ drop table t1; # create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; ---replace_column 8 # +--replace_column 8 # 12 # show table status like 't_'; drop table t1, t2; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index e5ca35bda32..1c1bf9fa6d3 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -230,7 +230,7 @@ DROP TABLE """a"; #set names latin1; #create database ``; #create table ``.`` (a int) engine=heap; -#--replace_column 7 # 8 # 9 # +#--replace_column 7 # 8 # 9 # 12 # #show table status from `` LIKE ''; #drop database ``; @@ -276,37 +276,37 @@ CREATE TABLE t3 ( insert into t1 values (1),(2); insert into t2 values (1),(2); insert into t3 values (1,1),(2,2); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (3),(4); insert into t2 values (3),(4); insert into t3 values (3,3),(4,4); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; delete from t1 where a=3; delete from t2 where b=3; delete from t3 where a=3; ---replace_column 6 # 7 # 8 # 9 # 10 # +--replace_column 6 # 7 # 8 # 9 # 10 # 12 # show table status; truncate table t1; truncate table t2; truncate table t3; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; delete from t1 where a=5; delete from t2 where b=5; delete from t3 where a=5; ---replace_column 6 # 7 # 8 # 9 # 10 # +--replace_column 6 # 7 # 8 # 9 # 10 # 12 # show table status; drop table t1, t2, t3; @@ -367,7 +367,7 @@ flush privileges; #set names latin1; #create database ``; #create table ``.`` (a int) engine=heap; -#--replace_column 7 # 8 # 9 # +#--replace_column 7 # 8 # 9 # 12 # #show table status from `` LIKE ''; #drop database ``; @@ -430,7 +430,7 @@ flush tables; # Create a junk frm file on disk let $MYSQLD_DATADIR= `select @@datadir`; system echo "this is a junk file for test" >> $MYSQLD_DATADIR/test/t1.frm ; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # SHOW TABLE STATUS like 't1'; --error ER_NOT_FORM_FILE show create table t1; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index d805fac2783..5d819722b6e 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -382,6 +382,7 @@ int ha_heap::info(uint flag) stats.index_file_length= hp_info.index_length; stats.max_data_file_length= hp_info.max_records * hp_info.reclength; stats.delete_length= hp_info.deleted * hp_info.reclength; + stats.create_time= (ulong) hp_info.create_time; if (flag & HA_STATUS_AUTO) stats.auto_increment_value= hp_info.auto_increment; /* diff --git a/storage/heap/hp_create.c b/storage/heap/hp_create.c index b6814fc1614..5208d4676c3 100644 --- a/storage/heap/hp_create.c +++ b/storage/heap/hp_create.c @@ -186,6 +186,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, share->auto_key= create_info->auto_key; share->auto_key_type= create_info->auto_key_type; share->auto_increment= create_info->auto_increment; + share->create_time= (long) time((time_t*) 0); /* Must be allocated separately for rename to work */ if (!(share->name= my_strdup(name,MYF(0)))) { diff --git a/storage/heap/hp_info.c b/storage/heap/hp_info.c index ea78c53fd40..c72dbaf2065 100644 --- a/storage/heap/hp_info.c +++ b/storage/heap/hp_info.c @@ -53,6 +53,7 @@ int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x, int flag ) x->index_length = info->s->index_length; x->max_records = info->s->max_records; x->errkey = info->errkey; + x->create_time = info->s->create_time; if (flag & HA_STATUS_AUTO) x->auto_increment= info->s->auto_increment + 1; DBUG_RETURN(0); From ab21828e1d2dea646a4833963b49c0943b3ec756 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 27 Sep 2011 19:21:40 +0200 Subject: [PATCH 118/143] Raising the version after cloning for the 5.5.17 build. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4ef9a31b64d..7bac52ecdfb 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=17 +MYSQL_VERSION_PATCH=18 MYSQL_VERSION_EXTRA= From ffd0a785f4e235c5fc633467b793686a79cf5237 Mon Sep 17 00:00:00 2001 From: Raghav Kapoor Date: Wed, 28 Sep 2011 15:39:21 +0530 Subject: [PATCH 119/143] BUG#11758062 - 50206: ER_TOO_BIG_SELECT REFERS TO OUTMODED SYSTEM VARIABLE NAME SQL_MAX_JOIN_SI BACKGROUND: ER_TOO_BIG_SELECT refers to SQL_MAX_JOIN_SIZE, which is the old name for MAX_JOIN_SIZE. FIX: Support for old name SQL_MAX_JOIN_SIZE is removed in MySQL 5.6 and is renamed as MAX_JOIN_SIZE.So the errmsg.txt and mysql.cc files have been updated and the corresponding result files have also been updated. --- client/mysql.cc | 2 +- mysql-test/r/select_safe.result | 12 ++++++------ .../suite/sys_vars/r/max_join_size_func.result | 4 ++-- .../suite/sys_vars/r/sql_big_selects_func.result | 2 +- .../suite/sys_vars/r/sql_max_join_size_func.result | 2 +- sql/share/errmsg.txt | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 0a6b4da34b0..49d58a832a2 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4290,7 +4290,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, { char init_command[100]; sprintf(init_command, - "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu", + "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,MAX_JOIN_SIZE=%lu", select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index feac9efcb13..d810271e337 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -30,7 +30,7 @@ ERROR HY000: You are using safe update mode and you tried to update a table with delete from t1 where a+0=1; ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; @@ -42,7 +42,7 @@ SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); SELECT * from t1 order by a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET SQL_BIG_SELECTS=1; SELECT * from t1 order by a; a b @@ -52,7 +52,7 @@ a b 5 a SET MAX_JOIN_SIZE=2; SELECT * from t1; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; a b @@ -82,12 +82,12 @@ insert into t1 select * from t1; insert into t1 select * from t1; set local max_join_size=8; select * from (select * from t1) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select 1 union select 2 union select 3) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/suite/sys_vars/r/max_join_size_func.result b/mysql-test/suite/sys_vars/r/max_join_size_func.result index bf535579433..0bf4f507b0c 100644 --- a/mysql-test/suite/sys_vars/r/max_join_size_func.result +++ b/mysql-test/suite/sys_vars/r/max_join_size_func.result @@ -41,7 +41,7 @@ id name id name SET @@session.max_join_size=8; ## Since total joins are more than max_join_size value so error will occur ## SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay '#--------------------FN_DYNVARS_079_03-------------------------#' ## Setting global value of variable ## SET @@global.max_join_size=8; @@ -52,7 +52,7 @@ SELECT @@global.max_join_size; 8 ## Since total joins are more than max_join_size value so error will occur ## SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay ## Dropping both the tables ## Drop table t1, t2; ## Restoring values ## diff --git a/mysql-test/suite/sys_vars/r/sql_big_selects_func.result b/mysql-test/suite/sys_vars/r/sql_big_selects_func.result index fc7e1f32e00..6d7138a1a99 100644 --- a/mysql-test/suite/sys_vars/r/sql_big_selects_func.result +++ b/mysql-test/suite/sys_vars/r/sql_big_selects_func.result @@ -19,7 +19,7 @@ INSERT INTO t2 VALUES('aa4','bb'); '#--------------------FN_DYNVARS_154_01-------------------------#' Expected error "Too big select" SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay Expected error The SELECT would examine more than MAX_JOIN_SIZE rows. '#--------------------FN_DYNVARS_154_02-------------------------#' SET SESSION SQL_BIG_SELECTS = 1; diff --git a/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result b/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result index 0e406f6611e..32a1c2f31e5 100644 --- a/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result +++ b/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result @@ -17,7 +17,7 @@ INSERT INTO t2 VALUES('aa4','bb'); '#--------------------FN_DYNVARS_161_01-------------------------#' SET SESSION sql_max_join_size=9; SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay Expected error The SELECT would examine more than MAX_JOIN_SIZE rows. '#--------------------FN_DYNVARS_161_02-------------------------#' SET SESSION SQL_BIG_SELECTS = 1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index bbae17c4327..7cb9d9ebcc1 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -2494,10 +2494,10 @@ ER_TOO_BIG_SELECT 42000 cze "Zadan-B SELECT by prochzel pli mnoho zznam a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v podku, pouijte SET SQL_BIG_SELECTS=1" dan "SELECT ville undersge for mange poster og ville sandsynligvis tage meget lang tid. Undersg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt" nla "Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is." - eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay" + eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay" est "SELECT lause peab lbi vaatama suure hulga kirjeid ja vtaks tenoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada ksku SET SQL_BIG_SELECTS=1" fre "SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vrifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien" - ger "Die Ausfhrung des SELECT wrde zu viele Datenstze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel berprfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden" + ger "Die Ausfhrung des SELECT wrde zu viele Datenstze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel berprfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET MAX_JOIN_SIZE=# verwenden" greek " SELECT . WHERE SET SQL_BIG_SELECTS=1 SELECT " hun "A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay" ita "La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto." From 8da99509449498658468051551eef820f92199d7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 29 Sep 2011 10:42:23 +0200 Subject: [PATCH 120/143] Bug #12373393 PB2 SHOULD ALLOW TO CREATE COLLECTIONS AS SUPER SET OF EXISTING COLLECTIONS Let CMake parse files with a ".in" suffix containing includes Added default.release.in to replace default.release Explained in README New patch: replace 'include' with '#include' to avoid accidental matches --- .bzrignore | 1 + mysql-test/CMakeLists.txt | 23 +++++++++++++++++++ mysql-test/collections/README | 8 +++++++ .../{default.release => default.release.in} | 6 +++++ 4 files changed, 38 insertions(+) rename mysql-test/collections/{default.release => default.release.in} (91%) diff --git a/.bzrignore b/.bzrignore index 017c41f2188..36bb062ffff 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1314,6 +1314,7 @@ mysql-max-4.0.2-alpha-pc-linux-gnu-i686.tar.gz mysql-test/*.ds? mysql-test/*.vcproj mysql-test/.DS_Store +mysql-test/collections/default.release mysql-test/funcs_1.log mysql-test/funcs_1.tar mysql-test/gmon.out diff --git a/mysql-test/CMakeLists.txt b/mysql-test/CMakeLists.txt index 655d8e086eb..954e9c44311 100644 --- a/mysql-test/CMakeLists.txt +++ b/mysql-test/CMakeLists.txt @@ -132,3 +132,26 @@ ADD_CUSTOM_TARGET(test-bt-debug COMMAND ${MTR_FORCE} --comment=debug --timer --skip-ndbcluster --skip-rpl --report-features ${EXP} ) +# Process .in files with includes in collections/ + +MACRO(PROCESS_COLLECTION_INCLUDE collin collection) + FILE(STRINGS ${collin} inlines) + FOREACH(line ${inlines}) + IF(${line} MATCHES "#include .*") + STRING(REPLACE "#include " "collections/" incfile ${line}) + FILE(READ ${incfile} contents) + FILE(APPEND ${collection} "${contents}") + ELSE() + FILE(APPEND ${collection} "${line}\n") + ENDIF() + ENDFOREACH() +ENDMACRO() + +FILE(GLOB infiles "collections/*.in") +FOREACH(collin ${infiles}) + STRING(REPLACE ".in" "" collection ${collin}) + # Only generate file once + IF(NOT EXISTS ${collection}) + PROCESS_COLLECTION_INCLUDE(${collin} ${collection}) + ENDIF() +ENDFOREACH() diff --git a/mysql-test/collections/README b/mysql-test/collections/README index 9af84646a40..f64c089ee99 100644 --- a/mysql-test/collections/README +++ b/mysql-test/collections/README @@ -28,3 +28,11 @@ these steps: 5) The commands from the collection are run line by line via execv() or similar system calls. They are not run as a shell script. Shell expansions are not guaranteed to work and most likely won't. + +The directory may contain collections that are "super sets" of others, +identified by a file name suffix ".in". These files may contain lines +"#include ", or lines with mysql-test-run.pl invocations. +CMake will create a new file without the .in suffix where +the include lines are replaced with the contents of the referred +file. Filename is local to the collections directory, and includes do +not nest. diff --git a/mysql-test/collections/default.release b/mysql-test/collections/default.release.in similarity index 91% rename from mysql-test/collections/default.release rename to mysql-test/collections/default.release.in index 108e1032ca2..0e3ad30671b 100644 --- a/mysql-test/collections/default.release +++ b/mysql-test/collections/default.release.in @@ -1,3 +1,9 @@ +# This file contains the old default.release, the plan is to replace that +# with something like the below (remove space after #): + +# include default.daily +# include default.weekly + perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=debug --vardir=var-debug --skip-ndbcluster --skip-rpl --report-features --debug-server perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=normal --vardir=var-normal --skip-ndbcluster --report-features perl mysql-test-run.pl --force --timer --parallel=auto --experimental=collections/default.experimental --comment=ps --vardir=var-ps --skip-ndbcluster --ps-protocol From 586c0c0ef6e23c4ce3c63f796187178f15e7010a Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Thu, 29 Sep 2011 14:47:27 +0530 Subject: [PATCH 121/143] BUG#11758262 - 50439: MARK INSERT...SEL...ON DUP KEY UPD,REPLACE...SEL,CREATE...[IGN|REPL] SEL Problem: The following statements can cause the slave to go out of sync if logged in statement format: INSERT IGNORE...SELECT INSERT ... SELECT ... ON DUPLICATE KEY UPDATE REPLACE ... SELECT UPDATE IGNORE : CREATE ... IGNORE SELECT CREATE ... REPLACE SELECT Background: Since the order of the rows returned by the SELECT statement or otherwise may differ on master and slave, therefore the above statements may cuase the salve to go out of sync with the master. Fix: Issue a warning when statements like the above are exectued and the bin-logging format is statement. If the logging format is mixed, use row based logging. Marking a statement as unsafe has been done in the sql/sql_parse.cc instead of sql/sql_yacc.cc, because while parsing for a token has been done we cannot be sure if the parsing of the other tokens has been done as well. Six new warning messages has been added for each unsafe statement. binlog.binlog_unsafe.test has been updated to incoporate these additional unsafe statments. ****** BUG#11758262 - 50439: MARK INSERT...SEL...ON DUP KEY UPD,REPLACE...SEL,CREATE...[IGN|REPL] SEL Problem: The following statements can cause the slave to go out of sync if logged in statement format: INSERT IGNORE...SELECT INSERT ... SELECT ... ON DUPLICATE KEY UPDATE REPLACE ... SELECT UPDATE IGNORE : CREATE ... IGNORE SELECT CREATE ... REPLACE SELECT Background: Since the order of the rows returned by the SELECT statement or otherwise may differ on master and slave, therefore the above statements may cuase the salve to go out of sync with the master. Fix: Issue a warning when statements like the above are exectued and the bin-logging format is statement. If the logging format is mixed, use row based logging. Marking a statement as unsafe has been done in the sql/sql_parse.cc instead of sql/sql_yacc.cc, because while parsing for a token has been done we cannot be sure if the parsing of the other tokens has been done as well. Six new warning messages has been added for each unsafe statement. binlog.binlog_unsafe.test has been updated to incoporate these additional unsafe statments. mysql-test/extra/rpl_tests/rpl_insert_duplicate.test: Test removed: Added the test to rpl.rpl_insert_ignore.test ****** Test removed: the test is redundant as the same is being tested in rpl.rpl_insert_ignore. mysql-test/extra/rpl_tests/rpl_insert_id.test: Warnings disabled for the unsafe statements. mysql-test/extra/rpl_tests/rpl_insert_ignore.test: 1. Disabled warnings while for unsafe statements 2. As INSERT...IGNORE is an unsafe statement, an insert ignore not changing any rows, will not be logged in the binary log, in the ROW and MIXED modes. It will however be logged in STATEMENT mode. mysql-test/r/commit_1innodb.result: updated result file ****** updated result file mysql-test/suite/binlog/r/binlog_stm_blackhole.result: Updated result file. mysql-test/suite/binlog/r/binlog_unsafe.result: updated result file mysql-test/suite/binlog/t/binlog_unsafe.test: added tests for the statements marked as unsafe. mysql-test/suite/rpl/r/rpl_insert_duplicate.result: File Removed :Result file of rpl_insert_duplicate, which has been removed. mysql-test/suite/rpl/r/rpl_insert_ignore.result: Added the content of rpl.rpl_insert_duplicate here. mysql-test/suite/rpl/r/rpl_insert_select.result: Result file removed as the corresponding test has beenn removed. mysql-test/suite/rpl/r/rpl_known_bugs_detection.result: Updated result file. mysql-test/suite/rpl/t/rpl_insert_duplicate.test: File Removed: this was a wrapper for rpl.rpl_insert_duplicate.test, which has been removed. mysql-test/suite/rpl/t/rpl_insert_select.test: File Removed: This test became redundant after this fix, This test showed how INSERT IGNORE...SELECT break replication, which has been handled in this fix. mysql-test/suite/rpl/t/rpl_known_bugs_detection.test: Since all the tests are statement based bugs are being tested, having mixed format forces the event to be written in row format. When the statement and causes the test to fail as certain known bugs do not occur when the even is logged in row format. sql/share/errmsg-utf8.txt: added 6 new Warning messages. ****** added 6 new Warning messages. sql/sql_lex.cc: Added 6 new error Identifier [ER_BINLOG_STMT_UNSAFEE_*] sql/sql_lex.h: Added 6 new BINLOG_STMT_UNSAFE_* enums to identify the type of unsafe statement dealt with in this bug. ****** Added 6 new BINLOG_STMT_UNSAFE_* enums to identify the type of unsafe statement dealt with in this bug. sql/sql_parse.cc: added check for specific queries and marked them as unsafe. ****** added check for specific queries and marked them as unsafe. --- .../extra/rpl_tests/rpl_insert_duplicate.test | 59 ------------------- mysql-test/extra/rpl_tests/rpl_insert_id.test | 29 +++++---- .../extra/rpl_tests/rpl_insert_ignore.test | 51 +++++++++++++++- mysql-test/r/commit_1innodb.result | 4 ++ .../binlog/r/binlog_stm_blackhole.result | 2 + .../suite/binlog/r/binlog_unsafe.result | 38 ++++++++++++ mysql-test/suite/binlog/t/binlog_unsafe.test | 48 +++++++++++++++ .../suite/rpl/r/rpl_insert_duplicate.result | 29 --------- .../suite/rpl/r/rpl_insert_ignore.result | 26 ++++++++ .../suite/rpl/r/rpl_insert_select.result | 14 ----- .../rpl/r/rpl_known_bugs_detection.result | 4 ++ .../suite/rpl/t/rpl_insert_duplicate.test | 14 ----- mysql-test/suite/rpl/t/rpl_insert_select.test | 20 ------- .../suite/rpl/t/rpl_known_bugs_detection.test | 2 +- sql/share/errmsg-utf8.txt | 18 ++++++ sql/sql_lex.cc | 6 ++ sql/sql_lex.h | 42 +++++++++++++ sql/sql_parse.cc | 40 +++++++++++++ 18 files changed, 294 insertions(+), 152 deletions(-) delete mode 100644 mysql-test/extra/rpl_tests/rpl_insert_duplicate.test delete mode 100644 mysql-test/suite/rpl/r/rpl_insert_duplicate.result delete mode 100644 mysql-test/suite/rpl/r/rpl_insert_select.result delete mode 100644 mysql-test/suite/rpl/t/rpl_insert_duplicate.test delete mode 100644 mysql-test/suite/rpl/t/rpl_insert_select.test diff --git a/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test b/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test deleted file mode 100644 index a81eeba3231..00000000000 --- a/mysql-test/extra/rpl_tests/rpl_insert_duplicate.test +++ /dev/null @@ -1,59 +0,0 @@ -# BUG#59338 Inconsistency in binlog for statements that don't change any rows STATEMENT SBR -# In SBR, if a statement does not fail, it is always written to the binary log, -# regardless if rows are changed or not. If there is a failure, a statement is -# only written to the binary log if a non-transactional (.e.g. MyIsam) engine -# is updated. INSERT ON DUPLICATE KEY UPDATE was not following the rule above -# and was not written to the binary log, if then engine was Innodb. -# -# In this test case, we check if INSERT ON DUPLICATE KEY UPDATE that does not -# change anything is still written to the binary log. - -# Prepare environment ---connection master - -eval CREATE TABLE t1 ( - a INT UNSIGNED NOT NULL PRIMARY KEY -) ENGINE=$engine_type; - -eval CREATE TABLE t2 ( - a INT UNSIGNED -) ENGINE=$engine_type; - -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); - -# An insert duplicate that does not update anything must be written to the binary -# log in SBR and MIXED modes. We check this property by summing a before and after -# the update and comparing the binlog positions. The sum should be the same at both -# points and the statement should be in the binary log. ---let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1) ---let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1) ---let $statement_file=INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a ---eval $statement_file - ---let $assert_cond= SUM(a) = 1 FROM t1 ---let $assert_text= Sum of elements in t1 should be 1. ---source include/assert.inc - -if (`SELECT @@BINLOG_FORMAT = 'ROW'`) -{ - --let $binlog_position_cmp= = - --let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start - --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. -} -if (`SELECT @@BINLOG_FORMAT != 'ROW'`) -{ - --let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 1, 1\', Info, 1]\' LIKE \'%$statement_file\' - --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. -} ---source include/assert.inc - -# Compare master and slave ---sync_slave_with_master ---let $diff_tables= master:test.t1 , slave:test.t1 ---source include/diff_tables.inc - -# Clean up ---connection master -drop table t1, t2; ---sync_slave_with_master diff --git a/mysql-test/extra/rpl_tests/rpl_insert_id.test b/mysql-test/extra/rpl_tests/rpl_insert_id.test index 565ab4a67ad..32d861bd45a 100644 --- a/mysql-test/extra/rpl_tests/rpl_insert_id.test +++ b/mysql-test/extra/rpl_tests/rpl_insert_id.test @@ -77,6 +77,7 @@ eval create table t2(b int auto_increment, c int, key(b)) engine=$engine_type; insert into t1 values (10); insert into t1 values (null),(null),(null); insert into t2 values (5,0); +--disable_warnings ONCE insert into t2 (c) select * from t1 ORDER BY a; select * from t2 ORDER BY b; sync_slave_with_master; @@ -113,8 +114,10 @@ set @@session.sql_auto_is_null=1; eval create table t1(a int auto_increment, key(a)) engine=$engine_type; eval create table t2(a int) engine=$engine_type; insert into t1 (a) values (null); +--disable_warnings insert into t2 (a) select a from t1 where a is null; insert into t2 (a) select a from t1 where a is null; +--enable_warnings select * from t2; sync_slave_with_master; connection slave; @@ -172,17 +175,15 @@ begin end| delimiter ;| ---disable_warnings +--disable_warnings ONCE insert into t1 (last_id) values (0); ---enable_warnings drop trigger t1_bi; # Check that nested call doesn't affect outer context. select last_insert_id(); ---disable_warnings +--disable_warnings ONCE select bug15728_insert(); ---enable_warnings select last_insert_id(); insert into t1 (last_id) values (bug15728()); # This should be exactly one greater than in the previous call. @@ -190,9 +191,8 @@ select last_insert_id(); # BUG#20339 - stored procedure using LAST_INSERT_ID() does not # replicate statement-based ---disable_warnings +--disable_warnings ONCE drop procedure if exists foo; ---enable_warnings delimiter |; create procedure foo() begin @@ -252,6 +252,7 @@ select * from t1 order by n; # table's counter, the counter for next row is bigger than the # after-value of the updated row. connection master; +--disable_warnings ONCE insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000; select * from t1 order by n; sync_slave_with_master; @@ -270,6 +271,7 @@ delete from t1 where b <> 100; select * from t1 order by n; connection master; +--disable_warnings ONCE insert into t1 values(null,100),(null,350) on duplicate key update n=2; select * from t1 order by n; sync_slave_with_master; @@ -287,6 +289,7 @@ connection master; # testcase with INSERT VALUES eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT, UNIQUE(b)) ENGINE=$engine_type; +--disable_warnings ONCE INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10; SELECT * FROM t1 ORDER BY a; sync_slave_with_master; @@ -314,19 +317,23 @@ INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c'); INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d'); INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e'); # Updating table t1 based on values from table t2 +--disable_warnings INSERT INTO t1 (field_1, field_2, field_3) SELECT t2.field_a, t2.field_b, t2.field_c FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c; +--enable_warnings # Inserting new record into t2 INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); # Updating t1 again +--disable_warnings INSERT INTO t1 (field_1, field_2, field_3) SELECT t2.field_a, t2.field_b, t2.field_c FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c; +--enable_warnings SELECT * FROM t1 ORDER BY id; sync_slave_with_master; SELECT * FROM t1 ORDER BY id; @@ -433,9 +440,8 @@ delimiter ;| INSERT INTO t1 VALUES (NULL, -1); CALL p1(); ---disable_warnings +--disable_warnings ONCE SELECT f1(); ---enable_warnings INSERT INTO t1 VALUES (NULL, f2()), (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID()), (NULL, f2()), (NULL, f2()); INSERT INTO t1 VALUES (NULL, f2()); @@ -504,16 +510,14 @@ insert into t2 (id) values(1),(2),(3); delete from t2; set sql_log_bin=1; #inside SELECT, then inside INSERT ---disable_warnings +--disable_warnings ONCE select insid(); ---enable_warnings set sql_log_bin=0; insert into t2 (id) values(5),(6),(7); delete from t2 where id>=5; set sql_log_bin=1; ---disable_warnings +--disable_warnings ONCE insert into t1 select insid(); ---enable_warnings select * from t1 order by id; select * from t2 order by id; @@ -537,6 +541,7 @@ begin insert into t2 values(null,3); end| delimiter ;| +--disable_warnings ONCE call foo(); select * from t1 order by n; select * from t2 order by id; diff --git a/mysql-test/extra/rpl_tests/rpl_insert_ignore.test b/mysql-test/extra/rpl_tests/rpl_insert_ignore.test index 270dde7675c..f422ef35f8c 100644 --- a/mysql-test/extra/rpl_tests/rpl_insert_ignore.test +++ b/mysql-test/extra/rpl_tests/rpl_insert_ignore.test @@ -31,7 +31,7 @@ INSERT INTO t2 VALUES (3, 5); INSERT INTO t2 VALUES (4, 3); INSERT INTO t2 VALUES (5, 4); INSERT INTO t2 VALUES (6, 6); - +--disable_warnings ONCE INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; --let $assert_cond= COUNT(*) = 6 FROM t1 --let $assert_text= Count of elements in t1 should be 6. @@ -51,25 +51,70 @@ INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; --let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1) --let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1) --let $statement_file=INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a +--disable_warnings ONCE --eval $statement_file --let $assert_cond= COUNT(*) = 6 FROM t1 --let $assert_text= Count of elements in t1 should be 6. --source include/assert.inc -if (`SELECT @@BINLOG_FORMAT = 'ROW'`) +if (`SELECT @@BINLOG_FORMAT != 'STATEMENT'`) { --let $binlog_position_cmp= = --let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. } -if (`SELECT @@BINLOG_FORMAT != 'ROW'`) +if (`SELECT @@BINLOG_FORMAT = 'STATEMENT'`) { --let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 2, 1\', Info, 1]\' LIKE \'%$statement_file\' --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. } + --source include/assert.inc +# An insert duplicate that does not update anything must be written to the binary +# log in SBR and MIXED modes. We check this property by summing a before and after +# the update and comparing the binlog positions. The sum should be the same at both +# points and the statement should be in the binary log. +--disable_warnings +DROP TABLE t1; +DROP TABLE t2; +--enable_warnings +eval CREATE TABLE t1 ( + a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=$engine_type; + +eval CREATE TABLE t2 ( + a INT UNSIGNED +) ENGINE=$engine_type; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +--let $binlog_file= query_get_value("SHOW MASTER STATUS", File, 1) +--let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1) +--let $statement_file=INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a +--disable_warnings ONCE +--eval $statement_file + +--let $assert_cond= SUM(a) = 1 FROM t1 +--let $assert_text= Sum of elements in t1 should be 1. +--source include/assert.inc + +if (`SELECT @@BINLOG_FORMAT != 'STATEMENT'`) +{ + --let $binlog_position_cmp= = + --let $assert_cond= [SHOW MASTER STATUS, Position, 1] $binlog_position_cmp $binlog_start + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +if (`SELECT @@BINLOG_FORMAT = 'STATEMENT'`) +{ + --let $assert_cond= \'[\'SHOW BINLOG EVENTS IN "$binlog_file" FROM $binlog_start LIMIT 1, 1\', Info, 1]\' LIKE \'%$statement_file\' + --let $assert_text= In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged. +} +--source include/assert.inc + + # Clean up --connection master drop table t1, t2; diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index fb1552b6c28..33fad9a0146 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -549,6 +549,8 @@ SUCCESS # 15. Read-write statement: UPDATE IGNORE, change 0 rows. # update ignore t1 set a=2 where a=1; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. call p_verify_status_increment(2, 2, 1, 0); SUCCESS @@ -814,6 +816,8 @@ SUCCESS insert into t2 select a from t1; commit; replace into t2 select a from t1; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. commit; call p_verify_status_increment(8, 8, 8, 8); SUCCESS diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index 7e79186e7bc..e76f6b494f9 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -99,6 +99,8 @@ alter table t1 drop b; create table t3 like t1; insert into t1 select * from t3; replace into t1 select * from t3; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. select * from t1; a select * from t2; diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index 9f35f09e220..a307b765097 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -2352,6 +2352,7 @@ Note 1592 Unsafe statement written to the binary log using statement format sinc REPLACE INTO t1 SELECT * FROM t1 LIMIT 1; Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. UPDATE t1 SET a=1 LIMIT 1; Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. @@ -2368,6 +2369,7 @@ END| CALL p1(); Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. DROP PROCEDURE p1; DROP TABLE t1; DROP TABLE IF EXISTS t1; @@ -2651,4 +2653,40 @@ a 13:46:40 1970-01-12 13:46:40 DROP TABLE t1; +CREATE TABLE filler_table (a INT, b INT); +INSERT INTO filler_table values (1,1),(1,2); +CREATE TABLE insert_table (a INT, b INT, PRIMARY KEY(a)); +CREATE TABLE replace_table (a INT, b INT, PRIMARY KEY(a)); +INSERT INTO replace_table values (1,1),(2,2); +CREATE TABLE update_table (a INT, b INT, PRIMARY KEY(a)); +INSERT INTO update_table values (1,1),(2,2); +INSERT IGNORE INTO insert_table SELECT * FROM filler_table; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT IGNORE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. +TRUNCATE TABLE insert_table; +INSERT INTO insert_table SELECT * FROM filler_table ON DUPLICATE KEY UPDATE a = 1; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave. +TRUNCATE TABLE insert_table; +REPLACE INTO replace_table SELECT * FROM filler_table; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. +UPDATE IGNORE update_table SET a=2; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. +CREATE TABLE create_ignore_test (a INT, b INT, PRIMARY KEY(b)) IGNORE SELECT * FROM filler_table; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. CREATE... IGNORE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. +CREATE TABLE create_replace_test (a INT, b INT, PRIMARY KEY(b)) REPLACE SELECT * FROM filler_table; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. CREATE... REPLACE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. +CREATE TEMPORARY TABLE temp1 (a INT, b INT, PRIMARY KEY(b)) REPLACE SELECT * FROM filler_table; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. CREATE... REPLACE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. +DROP TABLE filler_table; +DROP TABLE insert_table; +DROP TABLE update_table; +DROP TABLE replace_table; +DROP TABLE create_ignore_test; +DROP TABLE create_replace_test; "End of tests" diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test index 0dcf965112b..040f57597c2 100644 --- a/mysql-test/suite/binlog/t/binlog_unsafe.test +++ b/mysql-test/suite/binlog/t/binlog_unsafe.test @@ -12,6 +12,11 @@ # - insert into two autoinc columns; # - statements using UDF's. # - statements reading from log tables in the mysql database. +# - INSERT ... SELECT ... ON DUPLICATE KEY UPDATE +# - REPLACE ... SELECT +# - CREATE TABLE [IGNORE/REPLACE] SELECT +# - INSERT IGNORE...SELECT +# - UPDATE IGNORE # # Note that statements that use stored functions, stored procedures, # triggers, views, or prepared statements that invoke unsafe @@ -79,6 +84,7 @@ # BUG#45785: LIMIT in SP does not cause RBL if binlog_format=MIXED # BUG#47995: Mark user functions as unsafe # BUG#49222: Mark RAND() unsafe +# BUG#11758262: MARK INSERT...SEL...ON DUP KEY UPD,REPLACE...SEL,CREATE...[IGN|REPL] SEL # # ==== Related test cases ==== # @@ -699,5 +705,47 @@ INSERT INTO t1 VALUES SELECT * FROM t1; DROP TABLE t1; +# +#BUG#11758262-50439: MARK INSERT...SEL...ON DUP KEY UPD,REPLACE.. +#The following statement may be unsafe when logged in statement format. +#INSERT IGNORE...SELECT +#INSERT ... SELECT ... ON DUPLICATE KEY UPDATE +#REPLACE ... SELECT +#UPDATE IGNORE +#CREATE TABLE... IGNORE SELECT +#CREATE TABLE... REPLACE SELECT + +#setup tables +CREATE TABLE filler_table (a INT, b INT); +INSERT INTO filler_table values (1,1),(1,2); +CREATE TABLE insert_table (a INT, b INT, PRIMARY KEY(a)); +CREATE TABLE replace_table (a INT, b INT, PRIMARY KEY(a)); +INSERT INTO replace_table values (1,1),(2,2); +CREATE TABLE update_table (a INT, b INT, PRIMARY KEY(a)); +INSERT INTO update_table values (1,1),(2,2); + +#INSERT IGNORE... SELECT +INSERT IGNORE INTO insert_table SELECT * FROM filler_table; +TRUNCATE TABLE insert_table; +#INSERT ... SELECT ... ON DUPLICATE KEY UPDATE +INSERT INTO insert_table SELECT * FROM filler_table ON DUPLICATE KEY UPDATE a = 1; +TRUNCATE TABLE insert_table; +#REPLACE...SELECT +REPLACE INTO replace_table SELECT * FROM filler_table; +#UPDATE IGNORE +UPDATE IGNORE update_table SET a=2; +#CREATE TABLE [IGNORE/REPLACE] SELECT +CREATE TABLE create_ignore_test (a INT, b INT, PRIMARY KEY(b)) IGNORE SELECT * FROM filler_table; +CREATE TABLE create_replace_test (a INT, b INT, PRIMARY KEY(b)) REPLACE SELECT * FROM filler_table; +#temporary tables should not throw the warning. +CREATE TEMPORARY TABLE temp1 (a INT, b INT, PRIMARY KEY(b)) REPLACE SELECT * FROM filler_table; + +###clean up +DROP TABLE filler_table; +DROP TABLE insert_table; +DROP TABLE update_table; +DROP TABLE replace_table; +DROP TABLE create_ignore_test; +DROP TABLE create_replace_test; --echo "End of tests" diff --git a/mysql-test/suite/rpl/r/rpl_insert_duplicate.result b/mysql-test/suite/rpl/r/rpl_insert_duplicate.result deleted file mode 100644 index 61ebbaaa5a9..00000000000 --- a/mysql-test/suite/rpl/r/rpl_insert_duplicate.result +++ /dev/null @@ -1,29 +0,0 @@ -include/master-slave.inc -[connection master] -CREATE TABLE t1 ( -a INT UNSIGNED NOT NULL PRIMARY KEY -) ENGINE=innodb; -CREATE TABLE t2 ( -a INT UNSIGNED -) ENGINE=innodb; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; -include/assert.inc [Sum of elements in t1 should be 1.] -include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] -include/diff_tables.inc [master:test.t1 , slave:test.t1] -drop table t1, t2; -CREATE TABLE t1 ( -a INT UNSIGNED NOT NULL PRIMARY KEY -) ENGINE=myisam; -CREATE TABLE t2 ( -a INT UNSIGNED -) ENGINE=myisam; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; -include/assert.inc [Sum of elements in t1 should be 1.] -include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] -include/diff_tables.inc [master:test.t1 , slave:test.t1] -drop table t1, t2; -include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_insert_ignore.result b/mysql-test/suite/rpl/r/rpl_insert_ignore.result index 04b64359126..1598b3c059f 100644 --- a/mysql-test/suite/rpl/r/rpl_insert_ignore.result +++ b/mysql-test/suite/rpl/r/rpl_insert_ignore.result @@ -26,6 +26,19 @@ include/diff_tables.inc [master:test.t1 , slave:test.t1] INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; include/assert.inc [Count of elements in t1 should be 6.] include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] +DROP TABLE t1; +DROP TABLE t2; +CREATE TABLE t1 ( +a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=innodb; +CREATE TABLE t2 ( +a INT UNSIGNED +) ENGINE=innodb; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; +include/assert.inc [Sum of elements in t1 should be 1.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] drop table t1, t2; CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, @@ -52,5 +65,18 @@ include/diff_tables.inc [master:test.t1 , slave:test.t1] INSERT IGNORE INTO t1 SELECT NULL, t2.b FROM t2 ORDER BY t2.a; include/assert.inc [Count of elements in t1 should be 6.] include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] +DROP TABLE t1; +DROP TABLE t2; +CREATE TABLE t1 ( +a INT UNSIGNED NOT NULL PRIMARY KEY +) ENGINE=myisam; +CREATE TABLE t2 ( +a INT UNSIGNED +) ENGINE=myisam; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +INSERT INTO t1 SELECT t2.a FROM t2 ORDER BY t2.a ON DUPLICATE KEY UPDATE t1.a= t1.a; +include/assert.inc [Sum of elements in t1 should be 1.] +include/assert.inc [In SBR or MIXED modes, the event in the binlog should be the same that was executed. In RBR mode, binlog position should stay unchanged.] drop table t1, t2; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_insert_select.result b/mysql-test/suite/rpl/r/rpl_insert_select.result deleted file mode 100644 index d98ae2538fa..00000000000 --- a/mysql-test/suite/rpl/r/rpl_insert_select.result +++ /dev/null @@ -1,14 +0,0 @@ -include/master-slave.inc -[connection master] -create table t1 (n int not null primary key); -insert into t1 values (1); -create table t2 (n int); -insert into t2 values (1); -insert ignore into t1 select * from t2; -insert into t1 values (2); -select * from t1; -n -1 -2 -drop table t1,t2; -include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result index 43f5c082dea..92ccc78aaca 100644 --- a/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result +++ b/mysql-test/suite/rpl/r/rpl_known_bugs_detection.result @@ -42,12 +42,16 @@ SELECT t2.field_a, t2.field_b, t2.field_c FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave. INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f'); INSERT INTO t1 (field_1, field_2, field_3) SELECT t2.field_a, t2.field_b, t2.field_c FROM t2 ON DUPLICATE KEY UPDATE t1.field_3 = t2.field_c; +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave. SELECT * FROM t1; id field_1 field_2 field_3 1 1 a 1a diff --git a/mysql-test/suite/rpl/t/rpl_insert_duplicate.test b/mysql-test/suite/rpl/t/rpl_insert_duplicate.test deleted file mode 100644 index 7dd38a696ae..00000000000 --- a/mysql-test/suite/rpl/t/rpl_insert_duplicate.test +++ /dev/null @@ -1,14 +0,0 @@ -######################################### -# Wrapper for rpl_insert_duplicate.test # -######################################### --- source include/master-slave.inc --- source include/have_innodb.inc -#-- source include/have_binlog_format_mixed_or_statement.inc - -let $engine_type=innodb; --- source extra/rpl_tests/rpl_insert_duplicate.test - -let $engine_type=myisam; --- source extra/rpl_tests/rpl_insert_duplicate.test - ---source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_insert_select.test b/mysql-test/suite/rpl/t/rpl_insert_select.test deleted file mode 100644 index 23bc7ecd167..00000000000 --- a/mysql-test/suite/rpl/t/rpl_insert_select.test +++ /dev/null @@ -1,20 +0,0 @@ -# Testcase for BUG#10456 - INSERT INTO ... SELECT violating a primary key -# breaks replication - --- source include/master-slave.inc -connection master; - -create table t1 (n int not null primary key); -insert into t1 values (1); -create table t2 (n int); -insert into t2 values (1); -insert ignore into t1 select * from t2; -insert into t1 values (2); -sync_slave_with_master; -connection slave; -select * from t1; - -connection master; -drop table t1,t2; -sync_slave_with_master; ---source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test index f4b854eff87..99871b695a6 100644 --- a/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test +++ b/mysql-test/suite/rpl/t/rpl_known_bugs_detection.test @@ -7,7 +7,7 @@ source include/have_debug.inc; source include/master-slave.inc; # Currently only statement-based-specific bugs are here --- source include/have_binlog_format_mixed_or_statement.inc +-- source include/have_binlog_format_statement.inc # # This is to test that slave properly detects if diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c82215f41fb..da176bd5233 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6421,6 +6421,24 @@ ER_INDEX_CORRUPT ER_UNDO_RECORD_TOO_BIG eng "Undo log record is too big." +ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT + eng "INSERT IGNORE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave." + +ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE + eng "INSERT... SELECT... ON DUPLICATE KEY UPDATE is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are updated. This order cannot be predicted and may differ on master and the slave." + +ER_BINLOG_UNSAFE_REPLACE_SELECT + eng "REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave." + +ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT + eng "CREATE... IGNORE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave." + +ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT + eng "CREATE... REPLACE SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave." + +ER_BINLOG_UNSAFE_UPDATE_IGNORE + eng "UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave." + ER_PLUGIN_NO_UNINSTALL eng "Plugin '%s' is marked as not dynamically uninstallable. You have to stop the server to uninstall it." diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 14cf57af141..df27362633f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -59,6 +59,12 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] = ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS, ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE, ER_BINLOG_UNSAFE_MIXED_STATEMENT, + ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT, + ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE, + ER_BINLOG_UNSAFE_REPLACE_SELECT, + ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT, + ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT, + ER_BINLOG_UNSAFE_UPDATE_IGNORE }; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8794006fef7..542e8b42ae2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1253,6 +1253,48 @@ public: */ BINLOG_STMT_UNSAFE_MIXED_STATEMENT, + /** + INSERT...IGNORE SELECT is unsafe because which rows are ignored depends + on the order that rows are retrieved by SELECT. This order cannot be + predicted and may differ on master and the slave. + */ + BINLOG_STMT_UNSAFE_INSERT_IGNORE_SELECT, + + /** + INSERT...SELECT...UPDATE is unsafe because which rows are updated depends + on the order that rows are retrieved by SELECT. This order cannot be + predicted and may differ on master and the slave. + */ + BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE, + + /** + INSERT...REPLACE SELECT is unsafe because which rows are replaced depends + on the order that rows are retrieved by SELECT. This order cannot be + predicted and may differ on master and the slave. + */ + BINLOG_STMT_UNSAFE_REPLACE_SELECT, + + /** + CREATE TABLE... IGNORE... SELECT is unsafe because which rows are ignored + depends on the order that rows are retrieved by SELECT. This order cannot + be predicted and may differ on master and the slave. + */ + BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT, + + /** + CREATE TABLE...REPLACE... SELECT is unsafe because which rows are replaced + depends on the order that rows are retrieved from SELECT. This order + cannot be predicted and may differ on master and the slave + */ + BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT, + + /** + UPDATE...IGNORE is unsafe because which rows are ignored depends on the + order that rows are updated. This order cannot be predicted and may differ + on master and the slave. + */ + BINLOG_STMT_UNSAFE_UPDATE_IGNORE, + /* The last element of this enumeration type. */ BINLOG_STMT_UNSAFE_COUNT }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4df77b5b15b..4fac64749e9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2386,6 +2386,19 @@ case SQLCOM_PREPARE: { select_result *result; + /* + CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless + ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore + use row based logging if mixed or row based logging is available. + TODO: Check if the order of the output of the select statement is + deterministic. Waiting for BUG#42415 + */ + if(lex->ignore) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT); + + if(lex->duplicates == DUP_REPLACE) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT); + /* If: a) we inside an SP and there was NAME_CONST substitution, @@ -2720,6 +2733,16 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (update_precheck(thd, all_tables)) break; + + /* + UPDATE IGNORE can be unsafe. We therefore use row based + logging if mixed or row based logging is available. + TODO: Check if the order of the output of the select statement is + deterministic. Waiting for BUG#42415 + */ + if (lex->ignore) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_UPDATE_IGNORE); + DBUG_ASSERT(select_lex->offset_limit == 0); unit->set_limit(select_lex); MYSQL_UPDATE_START(thd->query()); @@ -2886,6 +2909,23 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; + /* + INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/ + INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY + clause is used in SELECT statement. We therefore use row based + logging if mixed or row based logging is available. + TODO: Check if the order of the output of the select statement is + deterministic. Waiting for BUG#42415 + */ + if (lex->sql_command == SQLCOM_INSERT_SELECT && + lex->duplicates == DUP_UPDATE) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE); + + if (lex->sql_command == SQLCOM_INSERT_SELECT && lex->ignore) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_IGNORE_SELECT); + + if (lex->sql_command == SQLCOM_REPLACE_SELECT) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_REPLACE_SELECT); /* Fix lock for first table */ if (first_table->lock_type == TL_WRITE_DELAYED) From 4d0da67aba2cfbddc5c246691841c1a4ca77a832 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 29 Sep 2011 12:30:14 +0200 Subject: [PATCH 122/143] removed some duplicate/redundant entries from .bzrignore --- .bzrignore | 68 ------------------------------------------------------ 1 file changed, 68 deletions(-) diff --git a/.bzrignore b/.bzrignore index 36bb062ffff..c54083a4209 100644 --- a/.bzrignore +++ b/.bzrignore @@ -43,7 +43,6 @@ *.vcxproj *.vcxproj.filters */*.dir/* -*.dir Debug MySql.sdf Win32 @@ -497,7 +496,6 @@ contrib/*.ds? contrib/*.vcproj core core.* -core.2430 cscope.in.out cscope.out cscope.po.out @@ -1336,81 +1334,17 @@ mysql-test/r/*.err mysql-test/r/*.log mysql-test/r/*.out mysql-test/r/*.reject -mysql-test/r/alter_table.err -mysql-test/r/archive.err -mysql-test/r/backup.log -mysql-test/r/bdb-alter-table-1.err -mysql-test/r/bdb-alter-table-2.err -mysql-test/r/bdb-crash.err -mysql-test/r/bdb-deadlock.err -mysql-test/r/bdb.err -mysql-test/r/bdb.log -mysql-test/r/bdb_cache.err -mysql-test/r/blackhole.log -mysql-test/r/client_test.err -mysql-test/r/csv.err -mysql-test/r/ctype_ucs.err -mysql-test/r/derived.err -mysql-test/r/events.log -mysql-test/r/events_bugs.log -mysql-test/r/events_logs_tests.log -mysql-test/r/exampledb.err -mysql-test/r/func_encrypt.err -mysql-test/r/im_client_port.log mysql-test/r/index_merge_load.result -mysql-test/r/isam.err -mysql-test/r/lowercase_table2.err mysql-test/r/max_allowed_packet_func.result -mysql-test/r/multi_update.err -mysql-test/r/mysql_protocols.err -mysql-test/r/mysqlbinlog.err -mysql-test/r/mysqlbinlog2.err -mysql-test/r/mysqldump.err -mysql-test/r/mysqltest.err -mysql-test/r/mysqltest.log -mysql-test/r/ndb_alter_table.err -mysql-test/r/ndb_autodiscover.err -mysql-test/r/ndb_autodiscover2.err -mysql-test/r/ndb_basic.err -mysql-test/r/ndb_blob.err -mysql-test/r/ndb_cache.err -mysql-test/r/ndb_charset.err -mysql-test/r/ndb_index.err -mysql-test/r/ndb_index_ordered.err -mysql-test/r/ndb_index_unique.err -mysql-test/r/ndb_insert.err -mysql-test/r/ndb_limit.err -mysql-test/r/ndb_lock.err -mysql-test/r/ndb_minmax.err -mysql-test/r/ndb_replace.err -mysql-test/r/ndb_subquery.err -mysql-test/r/ndb_transaction.err -mysql-test/r/ndb_truncate.err -mysql-test/r/ndb_types.err -mysql-test/r/ndb_update.err -mysql-test/r/openssl_1.err -mysql-test/r/ps_1general.err -mysql-test/r/ps_6bdb.err -mysql-test/r/ps_7ndb.err -mysql-test/r/query_cache.err -mysql-test/r/query_cache_merge.err -mysql-test/r/raid.err -mysql-test/r/repair.err -mysql-test/r/replace.err -mysql-test/r/rpl000001.err mysql-test/r/rpl000001.eval mysql-test/r/rpl000002.eval mysql-test/r/rpl000014.eval -mysql-test/r/rpl000015.err mysql-test/r/rpl000015.eval mysql-test/r/rpl000016.eval mysql-test/r/rpl_log.eval mysql-test/r/slave-running.eval mysql-test/r/slave-stopped.eval -mysql-test/r/symlink.log -mysql-test/r/system_mysql_db.log mysql-test/r/tmp.result -mysql-test/r/udf.log mysql-test/reg.log mysql-test/rpl.log mysql-test/share/mysql @@ -3105,9 +3039,7 @@ sql/share/swedish sql/share/ukrainian libmysqld/examples/mysqltest.cc libmysqld/sql_signal.cc -libmysqld/rpl_handler.cc libmysqld/debug_sync.cc -libmysqld/rpl_handler.cc dbug/tests libmysqld/mdl.cc client/transaction.h From 5aa1d312a4c5b6db498907a3a4ad65e11e753068 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 29 Sep 2011 12:34:44 +0200 Subject: [PATCH 123/143] mtr --help: add --boot-xxx and sort some debug options --- mysql-test/mysql-test-run.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d7ed9bb67ab..715276a221d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6074,11 +6074,15 @@ Options to run test on running server Options for debugging the product + boot-dbx Start bootstrap server in dbx + boot-ddd Start bootstrap server in ddd + boot-gdb Start bootstrap server in gdb + client-dbx Start mysqltest client in dbx client-ddd Start mysqltest client in ddd client-debugger=NAME Start mysqltest in the selected debugger client-gdb Start mysqltest client in gdb - client-dbx Start mysqltest client in dbx - ddd Start mysqld in ddd + dbx Start the mysqld(s) in dbx + ddd Start the mysqld(s) in ddd debug Dump trace output for all servers and client programs debug-common Same as debug, but sets 'd' debug flags to "query,info,error,enter,exit" @@ -6086,7 +6090,6 @@ Options for debugging the product tracing debugger=NAME Start mysqld in the selected debugger gdb Start the mysqld(s) in gdb - dbx Start the mysqld(s) in dbx manual-debug Let user manually start mysqld in debugger, before running test(s) manual-gdb Let user manually start mysqld in gdb, before running From 593c9457cd8533091ac1bad1e85234e79c0ce6a3 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 29 Sep 2011 14:14:43 +0300 Subject: [PATCH 124/143] Bug#11747416 : 32228 A disk full makes binary log corrupt Binary log of master can get a partially logged event if the server runs out of disk space and, while waiting for some space to be freed, is shut down (or crashes). If the server is not stopped, it will just wait endlessly for space to be freed, thus no partial event anomaly occurs. The restarted master server has had a dubious policy to send the incomplete event to slave which it apparently can't handle. Although an error was printed out the fact of sending with unclear error message is a source of confusion. Actually the problem of presence an incomplete event in the binary log was already fixed by WL 5493 (which was merged to our current trunk branch, major version 5.6). The fix makes the server truncate the binary log on server restart and recovery. However 5.5 master can't do that. So the current issue is a problem of sending incomplete events to the slave by 5.5 master. It is fixed in this patch by changing the policy so that only complete events are pushed by the dump thread to the IO thread. In addition, the error text that master sends to the slave when an incomplete event is found, now states that incomplete event may have been caused by an out-of-disk space situation and provides coordinates of the first and the last event bytes read. mysql-test/std_data/bug11747416_32228_binlog.000001: a binlog is added with the last event written partly. mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result: new result file is added. mysql-test/suite/rpl/r/rpl_log_pos.result: results updated. mysql-test/suite/rpl/r/rpl_manual_change_index_file.result: results updated. mysql-test/suite/rpl/r/rpl_packet.result: results updated. mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test: regression test for bug#11747416 : 32228 A disk full makes binary log corrupt is added. sql/share/errmsg-utf8.txt: Increasing the explanatory part of ER_MASTER_FATAL_ERROR_READING_BINLOG error message twice in order to fit to the updated version which carries some more info. sql/sql_repl.cc: Error text indicating a failure of reading from binlog that master delivers to the slave is made more clear; A policy to regard a partial event to send it out to the slave anyway is removed. --- .../std_data/bug11747416_32228_binlog.000001 | Bin 0 -> 8192 bytes .../rpl/r/rpl_cant_read_event_incident.result | 19 ++++++ mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- .../rpl/r/rpl_manual_change_index_file.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 2 +- .../rpl/t/rpl_cant_read_event_incident.test | 64 ++++++++++++++++++ sql/share/errmsg-utf8.txt | 16 ++--- sql/sql_repl.cc | 32 ++++----- 8 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 mysql-test/std_data/bug11747416_32228_binlog.000001 create mode 100644 mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result create mode 100644 mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test diff --git a/mysql-test/std_data/bug11747416_32228_binlog.000001 b/mysql-test/std_data/bug11747416_32228_binlog.000001 new file mode 100644 index 0000000000000000000000000000000000000000..2596b5b02372d421010320f601918868dcf06a61 GIT binary patch literal 8192 zcmeIuF-yZh6bJDC#Y1ipp&f)QCYv2va40(HB8s@grJGY?ju0$YuqWnQ`Vssh()eCV zW;;3kAG~l$?*1?N?W#6>e|E*G0nkXlNgG%!7t6)v)x7rAM>Ah<^wl4wG1Kc4I80!r zCcp|db#lx(mmuxBBGECm^w$ukcUl%m_p9*t- z7JV0InGa1H{B0Y;rmj}wjC+ZjN|=+M+1DX6?j9bWif75tqnJtG49D{!LRf|`F%jm+ zBt|!$>HBjT@?vx~ZZ!R_?@Ja1C_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC O1t>rP3Q*vm1bzW34bR*F literal 0 HcmV?d00001 diff --git a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result new file mode 100644 index 00000000000..f8ff9594dfa --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result @@ -0,0 +1,19 @@ +include/master-slave.inc +[connection master] +call mtr.add_suppression("Error in Log_event::read_log_event()"); +include/rpl_stop_server.inc [server_number=1] +include/rpl_start_server.inc [server_number=1] +show binlog events; +ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log"); +stop slave; +reset slave; +start slave; +include/wait_for_slave_param.inc [Last_IO_Errno] +Last_IO_Errno = '1236' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the last event was read from ./master-bin.000001 at 316, the last byte read was read from ./master-bin.000001 at 335.'' +reset master; +stop slave; +reset slave; +drop table t; +End of the tests diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 91d307008f0..753eb86be44 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: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the last event was read from ./master-bin.000001 at 75, the last byte read was read from ./master-bin.000001 at 94.'' 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_manual_change_index_file.result b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result index 23238d9c97b..479f84ef648 100644 --- a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result +++ b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result @@ -5,7 +5,7 @@ CREATE TABLE t1(c1 INT); FLUSH LOGS; call mtr.add_suppression('Got fatal error 1236 from master when reading data from binary log: .*could not find next log'); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from ./master-bin.000002 at 237, the last byte read was read from ./master-bin.000002 at 237.'' CREATE TABLE t2(c1 INT); FLUSH LOGS; CREATE TABLE t3(c1 INT); diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 6190f458367..03b2e3131e1 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -37,7 +37,7 @@ 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'' +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; the last event was read from ./master-bin.000001 at 463, the last byte read was read from ./master-bin.000001 at 482.'' STOP SLAVE; RESET SLAVE; RESET MASTER; diff --git a/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test new file mode 100644 index 00000000000..71445be55e6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_cant_read_event_incident.test @@ -0,0 +1,64 @@ +# +# Bug#11747416 : 32228 A disk full makes binary log corrupt. +# +# +# The test demonstrates reading from binlog error propagation to slave +# and reporting there. +# Conditions for the bug include a crash at time of the last event to +# the binlog was written partly. With the fixes the event is not sent out +# any longer, but rather the dump thread sends out a sound error message. +# +# Crash is not simulated. A binlog with partly written event in its end is installed +# and replication is started from it. +# + +--source include/master-slave.inc +--source include/have_binlog_format_mixed.inc + +call mtr.add_suppression("Error in Log_event::read_log_event()"); + +--connection master +--let $datadir= `SELECT @@datadir` + +--let $rpl_server_number= 1 +--source include/rpl_stop_server.inc + +--remove_file $datadir/master-bin.000001 +--copy_file $MYSQL_TEST_DIR/std_data/bug11747416_32228_binlog.000001 $datadir/master-bin.000001 + +--let $rpl_server_number= 1 +--source include/rpl_start_server.inc + +--source include/wait_until_connected_again.inc + +# evidence of the partial binlog +--error ER_ERROR_WHEN_EXECUTING_COMMAND +show binlog events; + +--connection slave +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log"); +stop slave; +reset slave; +start slave; + +# ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 +--let $slave_param=Last_IO_Errno +--let $slave_param_value=1236 +--source include/wait_for_slave_param.inc + +--let $status_items= Last_IO_Errno, Last_IO_Error +--source include/show_slave_status.inc + +# +# Cleanup +# + +--connection master +reset master; + +--connection slave +stop slave; +reset slave; +drop table t; # table was created from binlog. it does not exist on master. + +--echo End of the tests diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index da176bd5233..06d67db7aab 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -4701,14 +4701,14 @@ ER_NOT_SUPPORTED_YET 42000 spa "Esta versión de MySQL no soporta todavia '%s'" swe "Denna version av MySQL kan ännu inte utföra '%s'" ER_MASTER_FATAL_ERROR_READING_BINLOG - nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log" - eng "Got fatal error %d from master when reading data from binary log: '%-.128s'" - ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs" - ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario" - por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log" - rus "Получена неисправимая ошибка %d: '%-.128s' от головного сервера в процессе выборки данных из двоичного журнала" - spa "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log" - swe "Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen" + nla "Kreeg fatale fout %d: '%-.256s' van master tijdens lezen van data uit binaire log" + eng "Got fatal error %d from master when reading data from binary log: '%-.256s'" + ger "Schwerer Fehler %d: '%-.256s vom Master beim Lesen des binären Logs" + ita "Errore fatale %d: '%-.256s' dal master leggendo i dati dal log binario" + por "Obteve fatal erro %d: '%-.256s' do master quando lendo dados do binary log" + rus "Получена неисправимая ошибка %d: '%-.256s' от головного сервера в процессе выборки данных из двоичного журнала" + spa "Recibió fatal error %d: '%-.256s' del master cuando leyendo datos del binary log" + swe "Fick fatalt fel %d: '%-.256s' från master vid läsning av binärloggen" ER_SLAVE_IGNORED_TABLE eng "Slave SQL thread ignored the query because of replicate-*-table rules" ger "Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert" diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 8653607263f..c0d9432c71a 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -352,7 +352,7 @@ Increase max_allowed_packet on master"; *errmsg = "memory allocation failed reading log event"; break; case LOG_READ_TRUNC: - *errmsg = "binlog truncated in the middle of event"; + *errmsg = "binlog truncated in the middle of event; consider out of disk space on master"; break; default: *errmsg = "unknown error reading log event on the master"; @@ -447,6 +447,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, String* packet = &thd->packet; int error; const char *errmsg = "Unknown error"; + const char *fmt= "%s; the last event was read from %s at %s, the last byte read was read from %s at %s."; + char llbuff1[22], llbuff2[22]; + char error_text[MAX_SLAVE_ERRMSG]; // to be send to slave via my_message() NET* net = &thd->net; mysql_mutex_t *log_lock; mysql_cond_t *log_cond; @@ -677,10 +680,8 @@ impossible position"; if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) goto err; - my_off_t prev_pos= pos; - while (!(error = Log_event::read_log_event(&log, packet, log_lock))) + while (!(error= Log_event::read_log_event(&log, packet, log_lock))) { - prev_pos= my_b_tell(&log); #ifndef DBUG_OFF if (max_binlog_dump_events && !left_events--) { @@ -766,17 +767,6 @@ impossible position"; goto err; } - /* - here we were reading binlog that was not closed properly (as a result - of a crash ?). treat any corruption as EOF - */ - if (binlog_can_be_corrupted && - error != LOG_READ_MEM && error != LOG_READ_EOF) - { - my_b_seek(&log, prev_pos); - error=LOG_READ_EOF; - } - /* TODO: now that we are logging the offset, check to make sure the recorded offset and the actual match. @@ -1021,6 +1011,16 @@ end: err: thd_proc_info(thd, "Waiting to finalize termination"); + if (my_errno == ER_MASTER_FATAL_ERROR_READING_BINLOG && my_b_inited(&log)) + /* + detailing the fatal error message with coordinates + of the last position read. + */ + my_snprintf(error_text, sizeof(error_text), fmt, errmsg, + coord->file_name, (llstr(coord->pos, llbuff1), llbuff1), + log_file_name, (llstr(my_b_tell(&log), llbuff2), llbuff2)); + else + strcpy(error_text, errmsg); end_io_cache(&log); RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); /* @@ -1037,7 +1037,7 @@ err: mysql_file_close(file, MYF(MY_WME)); thd->variables.max_allowed_packet= old_max_allowed_packet; - my_message(my_errno, errmsg, MYF(0)); + my_message(my_errno, error_text, MYF(0)); DBUG_VOID_RETURN; } From 0c775ea96f7d1c990da6a6a54c75e6c1fc8ae047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 29 Sep 2011 15:31:46 +0300 Subject: [PATCH 125/143] Update the German error message translations (by Stefan Hinz) and fix some Swedish too. --- mysql-test/r/group_by.result | 2 +- mysql-test/r/having.result | 2 +- sql/share/errmsg-utf8.txt | 208 +++++++++++++++++++++-------------- 3 files changed, 127 insertions(+), 85 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 950de54b815..66c6790e7d9 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1676,7 +1676,7 @@ c (SELECT a FROM t1 WHERE b = c) SELECT b c, (SELECT a FROM t1 WHERE b = c) FROM t1 HAVING b = 10; -ERROR 42000: non-grouping field 'b' is used in HAVING clause +ERROR 42000: Non-grouping field 'b' is used in HAVING clause SELECT MAX(b) c, (SELECT a FROM t1 WHERE b = c) FROM t1 HAVING b = 10; diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index 1bbdd5011c4..5508ee5ed7d 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -419,7 +419,7 @@ select f1 from t1 group by f1 having max(f1)=f1; f1 set session sql_mode='ONLY_FULL_GROUP_BY'; select f1 from t1 having max(f1)=f1; -ERROR 42000: non-grouping field 'f1' is used in HAVING clause +ERROR 42000: Non-grouping field 'f1' is used in HAVING clause select f1 from t1 group by f1 having max(f1)=f1; f1 set session sql_mode=''; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 06d67db7aab..ec867b43ff1 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -5036,7 +5036,7 @@ ER_FEATURE_DISABLED ger "Das Feature '%s' ist ausgeschaltet, Sie müssen MySQL mit '%s' übersetzen, damit es verfügbar ist" por "O recurso '%s' foi desativado; você necessita MySQL construído com '%s' para ter isto funcionando" spa "El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando" - swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definerad" + swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definierad" ER_OPTION_PREVENTS_STATEMENT eng "The MySQL server is running with the %s option so it cannot execute this statement" ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen" @@ -5577,7 +5577,8 @@ ER_VIEW_OTHER_USER eng "You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer" ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.192s'@'%-.192s' zu erzeugen" ER_NO_SUCH_USER - eng "The user specified as a definer ('%-.64s'@'%-.64s') does not exist" + eng "The user specified as a definer ('%-.64s'@'%-.64s') does not exist" + ger "Der als Definierer angegebene Benutzer ('%-.64s'@'%-.64s') existiert nicht" ER_FORBID_SCHEMA_CHANGE eng "Changing schema from '%-.192s' to '%-.192s' is not allowed." ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt" @@ -5618,7 +5619,7 @@ ER_VIEW_RECURSIVE eng "`%-.192s`.`%-.192s` contains view recursion" ger "`%-.192s`.`%-.192s` enthält View-Rekursion" ER_NON_GROUPING_FIELD_USED 42000 - eng "non-grouping field '%-.192s' is used in %-.64s clause" + eng "Non-grouping field '%-.192s' is used in %-.64s clause" ger "In der %-.192s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet" ER_TABLE_CANT_HANDLE_SPKEYS eng "The used table type doesn't support SPATIAL indexes" @@ -5645,15 +5646,20 @@ ER_NON_INSERTABLE_TABLE eng "The target table %-.100s of the %s is not insertable-into" ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar" ER_ADMIN_WRONG_MRG_TABLE - eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist" + eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist" + ger "Tabelle '%-.64s' ist unterschiedlich definiert, nicht vom Typ MyISAM oder existiert nicht" ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT - eng "Too high level of nesting for select" + eng "Too high level of nesting for select" + ger "Zu tief verschachtelte SELECT-Anweisungen" ER_NAME_BECOMES_EMPTY - eng "Name '%-.64s' has become ''" + eng "Name '%-.64s' has become ''" + ger "Name '%-.64s' wurde zu ''" ER_AMBIGUOUS_FIELD_TERM - eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" + eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" + ger "Das erste Zeichen der Zeichenkette FIELDS TERMINATED ist mehrdeutig; bitte benutzen Sie nicht optionale und nicht leere FIELDS ENCLOSED BY" ER_FOREIGN_SERVER_EXISTS - eng "The foreign server, %s, you are trying to create already exists." + eng "The foreign server, %s, you are trying to create already exists." + ger "Der entfernte Server %s, den Sie versuchen zu erzeugen, existiert schon." ER_FOREIGN_SERVER_DOESNT_EXIST eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s" ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s" @@ -5678,8 +5684,8 @@ ER_PARTITION_SUBPARTITION_ERROR swe "Subpartitioner kan bara vara hash och key partitioner" ER_PARTITION_SUBPART_MIX_ERROR eng "Must define subpartitions on all partitions if on one partition" - ger "Unterpartitionen können nur Hash- oder Key-Partitionen sein" - swe "Subpartitioner mÃ¥ste definieras pÃ¥ alla partitioner om pÃ¥ en" + ger "Wenn Sie Unterpartitionen auf einer Partition definieren, müssen Sie das für alle Partitionen tun" + swe "Subpartitioner måste definieras på alla partitioner om på en" ER_PARTITION_WRONG_NO_PART_ERROR eng "Wrong number of partitions defined, mismatch with previous setting" ger "Falsche Anzahl von Partitionen definiert, stimmt nicht mit vorherigen Einstellungen überein" @@ -5854,7 +5860,7 @@ ER_CREATE_FILEGROUP_FAILED ger "Anlegen von %s fehlgeschlagen" ER_DROP_FILEGROUP_FAILED eng "Failed to drop %s" - ger "Löschen (drop) von %s fehlgeschlagen" + ger "Löschen von %s fehlgeschlagen" ER_TABLESPACE_AUTO_EXTEND_ERROR eng "The handler doesn't support autoextend of tablespaces" ger "Der Handler unterstützt keine automatische Erweiterung (Autoextend) von Tablespaces" @@ -5898,7 +5904,8 @@ ER_EVENT_ENDS_BEFORE_STARTS eng "ENDS is either invalid or before STARTS" ger "ENDS ist entweder ungültig oder liegt vor STARTS" ER_EVENT_EXEC_TIME_IN_THE_PAST - eng "Event execution time is in the past. Event has been disabled" + eng "Event execution time is in the past. Event has been disabled" + ger "Ausführungszeit des Events liegt in der Vergangenheit. Event wurde deaktiviert" ER_EVENT_OPEN_TABLE_FAILED eng "Failed to open mysql.event" ger "Öffnen von mysql.event fehlgeschlagen" @@ -5925,7 +5932,7 @@ ER_EVENT_DATA_TOO_LONG ger "Daten der Spalte '%s' zu lang" ER_DROP_INDEX_FK eng "Cannot drop index '%-.192s': needed in a foreign key constraint" - ger "Kann Index '%-.192s' nicht löschen: wird für einen Fremdschlüssel benötigt" + ger "Kann Index '%-.192s' nicht löschen: wird für eine Fremdschlüsselbeschränkung benötigt" # When using this error message, use the ER_WARN_DEPRECATED_SYNTAX error # code. ER_WARN_DEPRECATED_SYNTAX_WITH_VER @@ -5936,10 +5943,10 @@ ER_CANT_WRITE_LOCK_LOG_TABLE ger "Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff möglich" ER_CANT_LOCK_LOG_TABLE eng "You can't use locks with log tables." - ger "Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL" + ger "Log-Tabellen können nicht gesperrt werden." ER_FOREIGN_DUPLICATE_KEY 23000 S1009 eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry" - ger "Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen" + ger "Aufrechterhalten der Fremdschlüssel-Beschränkungen für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen" ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error." ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie mysql_upgrade, um den Fehler zu beheben" @@ -5995,6 +6002,7 @@ ER_CANT_ACTIVATE_LOG ger "Kann Logdatei '%-.64s' nicht aktivieren" ER_RBR_NOT_AVAILABLE eng "The server was not built with row-based replication" + ger "Der Server wurde nicht mit zeilenbasierter Replikation gebaut" ER_BASE64_DECODE_ERROR eng "Decoding of base64 string failed" swe "Avkodning av base64 sträng misslyckades" @@ -6016,7 +6024,7 @@ ER_BAD_LOG_STATEMENT ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist" ER_CANT_RENAME_LOG_TABLE eng "Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'" - ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'" + ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen zwei Tabellen umbenannt werden: die Logtabelle zu einer Archivtabelle, und eine weitere Tabelle zu '%s'" ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000 eng "Incorrect parameter count in the call to native function '%-.192s'" ger "Falsche Anzahl von Parametern beim Aufruf der nativen Funktion '%-.192s'" @@ -6057,206 +6065,240 @@ ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009 swe "Dubbel nyckel '%-.64s' för nyckel '%-.192s'" ukr "Дублюючий запис '%-.64s' для ключа '%-.192s'" ER_BINLOG_PURGE_EMFILE - eng "Too many files opened, please execute the command again" - ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus" + eng "Too many files opened, please execute the command again" + ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus" ER_EVENT_CANNOT_CREATE_IN_THE_PAST - eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." + eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." + ger "Ausführungszeit des Events liegt in der Vergangenheit, und es wurde ON COMPLETION NOT PRESERVE gesetzt. Das Event wurde unmittelbar nach Erzeugung gelöscht." ER_EVENT_CANNOT_ALTER_IN_THE_PAST - eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." + eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." + ger "Ausführungszeit des Events liegt in der Vergangenheit, und es wurde ON COMPLETION NOT PRESERVE gesetzt. Das Event wurde unmittelbar nach Erzeugung gelöscht." ER_SLAVE_INCIDENT - eng "The incident %s occured on the master. Message: %-.64s" + eng "The incident %s occured on the master. Message: %-.64s" + ger "Der Vorfall %s passierte auf dem Master. Meldung: %-.64s" ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT - eng "Table has no partition for some existing values" + eng "Table has no partition for some existing values" + ger "Tabelle hat für einige bestehende Werte keine Partition" ER_BINLOG_UNSAFE_STATEMENT - eng "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s" + eng "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s" + swe "Detta är inte säkert att logga i statement-format, för BINLOG_FORMAT = STATEMENT. %s" + ger "Unsichere Anweisung ins Binärlog geschrieben, weil Anweisungsformat BINLOG_FORMAT = STATEMENT. %s" ER_SLAVE_FATAL_ERROR - eng "Fatal error: %s" + eng "Fatal error: %s" + ger "Fataler Fehler: %s" ER_SLAVE_RELAY_LOG_READ_FAILURE - eng "Relay log read failure: %s" + eng "Relay log read failure: %s" + ger "Relaylog-Lesefehler: %s" ER_SLAVE_RELAY_LOG_WRITE_FAILURE - eng "Relay log write failure: %s" + eng "Relay log write failure: %s" + ger "Relaylog-Schreibfehler: %s" ER_SLAVE_CREATE_EVENT_FAILURE - eng "Failed to create %s" + eng "Failed to create %s" + ger "Erzeugen von %s fehlgeschlagen" ER_SLAVE_MASTER_COM_FAILURE - eng "Master command %s failed: %s" + eng "Master command %s failed: %s" + ger "Master-Befehl %s fehlgeschlagen: %s" ER_BINLOG_LOGGING_IMPOSSIBLE - eng "Binary logging not possible. Message: %s" - + eng "Binary logging not possible. Message: %s" + ger "Binärlogging nicht möglich. Meldung: %s" ER_VIEW_NO_CREATION_CTX eng "View `%-.64s`.`%-.64s` has no creation context" + ger "View `%-.64s`.`%-.64s` hat keinen Erzeugungskontext" ER_VIEW_INVALID_CREATION_CTX eng "Creation context of view `%-.64s`.`%-.64s' is invalid" - + ger "Erzeugungskontext des Views`%-.64s`.`%-.64s' ist ungültig" ER_SR_INVALID_CREATION_CTX eng "Creation context of stored routine `%-.64s`.`%-.64s` is invalid" - + ger "Erzeugungskontext der gespeicherten Routine`%-.64s`.`%-.64s` ist ungültig" ER_TRG_CORRUPTED_FILE eng "Corrupted TRG file for table `%-.64s`.`%-.64s`" + ger "Beschädigte TRG-Datei für Tabelle `%-.64s`.`%-.64s`" ER_TRG_NO_CREATION_CTX eng "Triggers for table `%-.64s`.`%-.64s` have no creation context" + ger "Trigger für Tabelle `%-.64s`.`%-.64s` haben keinen Erzeugungskontext" ER_TRG_INVALID_CREATION_CTX eng "Trigger creation context of table `%-.64s`.`%-.64s` is invalid" - + ger "Trigger-Erzeugungskontext der Tabelle `%-.64s`.`%-.64s` ist ungültig" ER_EVENT_INVALID_CREATION_CTX eng "Creation context of event `%-.64s`.`%-.64s` is invalid" - + ger "Erzeugungskontext des Events `%-.64s`.`%-.64s` ist ungültig" ER_TRG_CANT_OPEN_TABLE eng "Cannot open table for trigger `%-.64s`.`%-.64s`" - + ger "Kann Tabelle für den Trigger `%-.64s`.`%-.64s` nicht öffnen" ER_CANT_CREATE_SROUTINE eng "Cannot create stored routine `%-.64s`. Check warnings" + ger "Kann gespeicherte Routine `%-.64s` nicht erzeugen. Beachten Sie die Warnungen" ER_NEVER_USED eng "Ambiguous slave modes combination. %s" - + ger "Mehrdeutige Kombination von Slave-Modi. %s" ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." + ger "Der BINLOG-Anweisung vom Typ `%s` ging keine BINLOG-Anweisung zur Formatbeschreibung voran." ER_SLAVE_CORRUPT_EVENT eng "Corrupted replication event was detected" - + ger "Beschädigtes Replikationsereignis entdeckt" ER_LOAD_DATA_INVALID_COLUMN eng "Invalid column reference (%-.64s) in LOAD DATA" - -ER_LOG_PURGE_NO_FILE + ger "Ungültige Spaltenreferenz (%-.64s) bei LOAD DATA" +ER_LOG_PURGE_NO_FILE eng "Being purged log %s was not found" - + ger "Zu bereinigende Logdatei %s wurde nicht gefunden" ER_XA_RBTIMEOUT XA106 - eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" - + eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" + ger "XA_RBTIMEOUT: Transaktionszweig wurde zurückgerollt: Zeitüberschreitung" ER_XA_RBDEADLOCK XA102 - eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" - + eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" + ger "XA_RBDEADLOCK: Transaktionszweig wurde zurückgerollt: Deadlock entdeckt" ER_NEED_REPREPARE eng "Prepared statement needs to be re-prepared" - -ER_DELAYED_NOT_SUPPORTED + ger "Vorbereitete Anweisungen müssen noch einmal vorbereitet werden" +ER_DELAYED_NOT_SUPPORTED eng "DELAYED option not supported for table '%-.192s'" - + ger "Die DELAYED-Option wird für Tabelle '%-.192s' nicht unterstützt" WARN_NO_MASTER_INFO eng "The master info structure does not exist" - + ger "Die Master-Info-Struktur existiert nicht" WARN_OPTION_IGNORED eng "<%-.64s> option ignored" - + ger "Option <%-.64s> ignoriert" WARN_PLUGIN_DELETE_BUILTIN eng "Built-in plugins cannot be deleted" - + ger "Eingebaute Plugins können nicht gelöscht werden" WARN_PLUGIN_BUSY eng "Plugin is busy and will be uninstalled on shutdown" - + ger "Plugin wird verwendet und wird erst beim Herunterfahren deinstalliert" ER_VARIABLE_IS_READONLY eng "%s variable '%s' is read-only. Use SET %s to assign the value" - + ger "%s Variable '%s' ist nur lesbar. Benutzen Sie SET %s, um einen Wert zuzuweisen" ER_WARN_ENGINE_TRANSACTION_ROLLBACK eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted" - + ger "Speicher-Engine %s unterstützt für diese Anweisung kein Rollback. Transaktion wurde zurückgerollt und muss neu gestartet werden" ER_SLAVE_HEARTBEAT_FAILURE eng "Unexpected master's heartbeat data: %s" + ger "Unerwartete Daten vom Heartbeat des Masters: %s" ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)." - ER_NDB_REPLICATION_SCHEMA_ERROR - eng "Bad schema for mysql.ndb_replication table. Message: %-.64s" + eng "Bad schema for mysql.ndb_replication table. Message: %-.64s" + ger "Fehlerhaftes Schema für mysql.ndb_replication table. Meldung: %-.64s" ER_CONFLICT_FN_PARSE_ERROR - eng "Error in parsing conflict function. Message: %-.64s" + eng "Error in parsing conflict function. Message: %-.64s" + ger "Fehler beim Parsen einer Konflikt-Funktion. Meldung: %-.64s" ER_EXCEPTIONS_WRITE_ERROR - eng "Write to exceptions table failed. Message: %-.128s"" - + eng "Write to exceptions table failed. Message: %-.128s"" + ger "Schreiben in Ausnahme-Tabelle fehlgeschlagen. Meldung: %-.128s"" ER_TOO_LONG_TABLE_COMMENT eng "Comment for table '%-.64s' is too long (max = %lu)" por "Comentário para a tabela '%-.64s' é longo demais (max = %lu)" - + ger "Kommentar für Tabelle '%-.64s' ist zu lang (max = %lu)" ER_TOO_LONG_FIELD_COMMENT eng "Comment for field '%-.64s' is too long (max = %lu)" por "Comentário para o campo '%-.64s' é longo demais (max = %lu)" - + ger "Kommentar für Feld '%-.64s' ist zu lang (max = %lu)" ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" - + ger "FUNCTION %s existiert nicht. Erläuterungen im Abschnitt 'Function Name Parsing and Resolution' im Referenzhandbuch" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # sql_table.h with the new maximal additional length for explain_filename. ER_DATABASE_NAME eng "Database" swe "Databas" + ger "Datenbank" ER_TABLE_NAME eng "Table" swe "Tabell" + ger "Tabelle" ER_PARTITION_NAME eng "Partition" swe "Partition" + ger "Partition" ER_SUBPARTITION_NAME eng "Subpartition" swe "Subpartition" + ger "Unterpartition" ER_TEMPORARY_NAME eng "Temporary" swe "Temporär" + ger "Temporär" ER_RENAMED_NAME eng "Renamed" swe "Namnändrad" + ger "Umbenannt" ER_TOO_MANY_CONCURRENT_TRXS eng "Too many active concurrent transactions" - + ger "Zu viele aktive simultane Transaktionen" WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" - + ger "Nicht-ASCII-Trennargumente werden nicht vollständig unterstützt" ER_DEBUG_SYNC_TIMEOUT eng "debug sync point wait timed out" ger "Debug Sync Point Wartezeit überschritten" ER_DEBUG_SYNC_HIT_LIMIT eng "debug sync point hit limit reached" ger "Debug Sync Point Hit Limit erreicht" - ER_DUP_SIGNAL_SET 42000 - eng "Duplicate condition information item '%s'" - + eng "Duplicate condition information item '%s'" + ger "Informationselement '%s' für Duplikatbedingung" # Note that the SQLSTATE is not 01000, it is provided by SIGNAL/RESIGNAL ER_SIGNAL_WARN 01000 - eng "Unhandled user-defined warning condition" - + eng "Unhandled user-defined warning condition" + ger "Unbehandelte benutzerdefinierte Warnbedingung" # Note that the SQLSTATE is not 02000, it is provided by SIGNAL/RESIGNAL ER_SIGNAL_NOT_FOUND 02000 - eng "Unhandled user-defined not found condition" - + eng "Unhandled user-defined not found condition" + ger "Unbehandelte benutzerdefinierte Nicht-gefunden-Bedingung" # Note that the SQLSTATE is not HY000, it is provided by SIGNAL/RESIGNAL ER_SIGNAL_EXCEPTION HY000 - eng "Unhandled user-defined exception condition" - + eng "Unhandled user-defined exception condition" + ger "Unbehandelte benutzerdefinierte Ausnahmebedingung" ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 0K000 - eng "RESIGNAL when handler not active" - + eng "RESIGNAL when handler not active" + ger "RESIGNAL bei nicht aktivem Handler" ER_SIGNAL_BAD_CONDITION_TYPE - eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" - + eng "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" + ger "SIGNAL/RESIGNAL kann nur mit einer Bedingung (CONDITION) benutzt werden, die bei SQLSTATE definiert wurde" WARN_COND_ITEM_TRUNCATED - eng "Data truncated for condition item '%s'" - + eng "Data truncated for condition item '%s'" + ger "Daten gekürzt für Bedingungselement '%s'" ER_COND_ITEM_TOO_LONG - eng "Data too long for condition item '%s'" - + eng "Data too long for condition item '%s'" + ger "Daten zu lang für Bedingungselement '%s'" ER_UNKNOWN_LOCALE - eng "Unknown locale: '%-.64s'" - + eng "Unknown locale: '%-.64s'" + ger "Unbekannte Locale: '%-.64s'" ER_SLAVE_IGNORE_SERVER_IDS eng "The requested server id %d clashes with the slave startup option --replicate-same-server-id" + ger "Die angeforderte Server-ID %d steht im Konflikt mit der Startoption --replicate-same-server-id für den Slave" ER_QUERY_CACHE_DISABLED eng "Query cache is disabled; restart the server with query_cache_type=1 to enable it" + ger "Abfragen-Cache ist deaktiviert. Starten Sie den Server neu mit query_cache_type=1, um ihn zu aktivieren" ER_SAME_NAME_PARTITION_FIELD eng "Duplicate partition field name '%-.192s'" + ger "Partitionsfeld '%-.192s' ist ein Duplikat" ER_PARTITION_COLUMN_LIST_ERROR eng "Inconsistency in usage of column lists for partitioning" + ger "Inkonsistenz bei der Benutzung von Spaltenlisten für Partitionierung" ER_WRONG_TYPE_COLUMN_VALUE_ERROR eng "Partition column values of incorrect type" + ger "Partitionsspaltenwerte sind vom falschen Typ" ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eng "Too many fields in '%-.192s'" + ger "Zu viele Felder in '%-.192s'" ER_MAXVALUE_IN_VALUES_IN eng "Cannot use MAXVALUE as value in VALUES IN" + ger "MAXVALUE kann nicht als Wert in VALUES IN verwendet werden" ER_TOO_MANY_VALUES_ERROR eng "Cannot have more than one value for this type of %-.64s partitioning" + ger "Für den Partionierungstyp %-.64s darf es nicht mehr als einen Wert geben" ER_ROW_SINGLE_PARTITION_FIELD_ERROR eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" + ger "Zeilenausdrücke in VALUES IN sind nur für Mehrfeld-Spaltenpartionierung erlaubt" ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD eng "Field '%-.192s' is of a not allowed type for this type of partitioning" + ger "Feld '%-.192s' ist für diese Art von Partitionierung von einem nicht zulässigen Typ" ER_PARTITION_FIELDS_TOO_LONG eng "The total length of the partitioning fields is too large" + ger "Die Gesamtlänge der Partitionsfelder ist zu groß" ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE eng "Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved." ER_BINLOG_ROW_MODE_AND_STMT_ENGINE @@ -6318,7 +6360,7 @@ ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT eng "Cannot change the binlog direct flag inside a stored function or trigger" ER_SPATIAL_MUST_HAVE_GEOM_COL 42000 eng "A SPATIAL index may only contain a geometrical type column" - + ger "Ein raumbezogener Index (SPATIAL) darf nur Spalten geometrischen Typs enthalten" ER_TOO_LONG_INDEX_COMMENT eng "Comment for index '%-.64s' is too long (max = %lu)" From 546cea3fd2bdcc76ab395686ec9a20fa0327e66f Mon Sep 17 00:00:00 2001 From: Rafal Somla Date: Thu, 29 Sep 2011 17:02:16 +0200 Subject: [PATCH 126/143] Bug#12982926 CLIENT CAN OVERRIDE ZERO-LENGTH-ALLOCATE BUFFER Changes in client plugin needed for testing the issue (test instrumentation). --- libmysql/authentication_win/handshake_client.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libmysql/authentication_win/handshake_client.cc b/libmysql/authentication_win/handshake_client.cc index 565726651cb..02e5483da29 100644 --- a/libmysql/authentication_win/handshake_client.cc +++ b/libmysql/authentication_win/handshake_client.cc @@ -161,6 +161,21 @@ int Handshake_client::write_packet(Blob &data) keep all the data. */ unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0); + +#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB) + + /* + For testing purposes, use wrong block count to see how server + handles this. + */ + DBUG_EXECUTE_IF("winauth_first_packet_test",{ + block_count= data.len() == 601 ? 0 : + data.len() == 602 ? 1 : + block_count; + }); + +#endif + DBUG_ASSERT(block_count < (unsigned)0x100); saved_byte= data[254]; data[254] = block_count; From 0e6afc7f6b1fef4e639f2012332c46301d3af1cb Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Fri, 30 Sep 2011 15:16:35 +0530 Subject: [PATCH 127/143] BUG#11758262 BUG#13043055 Problem: commit_1innodb fails on pb2 after the patch for BUG#11758262 Background: Certain statements threw warnings only in statement mode causing the result cintent mismatch. Fix: disabled warnings from the statements. --- mysql-test/include/commit.inc | 6 ++++++ mysql-test/r/commit_1innodb.result | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc index 9df1571a849..e84ad0f940d 100644 --- a/mysql-test/include/commit.inc +++ b/mysql-test/include/commit.inc @@ -521,7 +521,9 @@ commit; call p_verify_status_increment(2, 2, 2, 2); --echo # 15. Read-write statement: UPDATE IGNORE, change 0 rows. --echo # +--disable_warnings update ignore t1 set a=2 where a=1; +--enable_warnings call p_verify_status_increment(2, 2, 1, 0); commit; call p_verify_status_increment(2, 2, 1, 0); @@ -603,7 +605,9 @@ call p_verify_status_increment(2, 0, 1, 0); --echo # 21. Read-write statement: UPDATE, change 0 (transactional) rows. --echo # +--disable_warnings update t1 set a=2 where a=f1()+10; +--enable_warnings call p_verify_status_increment(2, 0, 1, 0); commit; call p_verify_status_increment(2, 0, 1, 0); @@ -703,7 +707,9 @@ call p_verify_status_increment(4, 4, 4, 4); --echo # insert into t2 select a from t1; commit; +--disable_warnings replace into t2 select a from t1; +--enable_warnings commit; call p_verify_status_increment(8, 8, 8, 8); # diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index 33fad9a0146..fb1552b6c28 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -549,8 +549,6 @@ SUCCESS # 15. Read-write statement: UPDATE IGNORE, change 0 rows. # update ignore t1 set a=2 where a=1; -Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. UPDATE IGNORE is unsafe because the order in which rows are updated determines which (if any) rows are ignored. This order cannot be predicted and may differ on master and the slave. call p_verify_status_increment(2, 2, 1, 0); SUCCESS @@ -816,8 +814,6 @@ SUCCESS insert into t2 select a from t1; commit; replace into t2 select a from t1; -Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. REPLACE... SELECT is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are replaced. This order cannot be predicted and may differ on master and the slave. commit; call p_verify_status_increment(8, 8, 8, 8); SUCCESS From c95fdd936e73eb3bddad3fe02d087ccce67b00c9 Mon Sep 17 00:00:00 2001 From: Inaam Rana Date: Fri, 30 Sep 2011 07:02:19 -0400 Subject: [PATCH 128/143] Revert original fix for Bug 12612184 and the follow up fix for Bug 12704861. Bug 12704861 fix was revno: 3504.1.1 (rb://693) Bug 12612184 fix was revno: 3445.1.10 (rb://678) --- storage/innobase/btr/btr0btr.c | 272 ++++---------------------- storage/innobase/btr/btr0cur.c | 140 ++++--------- storage/innobase/buf/buf0buf.c | 25 +++ storage/innobase/fsp/fsp0fsp.c | 234 +++++++++------------- storage/innobase/include/btr0btr.h | 49 +---- storage/innobase/include/btr0cur.h | 44 ++--- storage/innobase/include/btr0cur.ic | 4 +- storage/innobase/include/buf0buf.h | 36 +--- storage/innobase/include/buf0buf.ic | 17 +- storage/innobase/include/fsp0fsp.h | 30 ++- storage/innobase/include/mtr0mtr.h | 15 +- storage/innobase/include/mtr0mtr.ic | 8 +- storage/innobase/include/page0cur.ic | 5 +- storage/innobase/include/page0page.h | 39 +--- storage/innobase/include/page0page.ic | 32 +-- storage/innobase/include/rem0rec.h | 4 +- storage/innobase/include/rem0rec.ic | 4 +- storage/innobase/include/sync0rw.ic | 10 +- storage/innobase/include/sync0sync.h | 6 +- storage/innobase/include/univ.i | 5 +- storage/innobase/mtr/mtr0mtr.c | 7 +- storage/innobase/page/page0cur.c | 17 +- storage/innobase/page/page0page.c | 52 ++--- storage/innobase/row/row0ins.c | 61 +----- storage/innobase/row/row0row.c | 28 +-- storage/innobase/row/row0upd.c | 40 ++-- storage/innobase/row/row0vers.c | 16 +- storage/innobase/sync/sync0rw.c | 4 +- storage/innobase/sync/sync0sync.c | 12 +- storage/innobase/trx/trx0rec.c | 4 +- storage/innobase/trx/trx0undo.c | 4 +- 31 files changed, 366 insertions(+), 858 deletions(-) diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 6a6f0025fa5..b476167af29 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -906,29 +906,28 @@ btr_page_alloc_for_ibuf( /**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! -@return allocated page number, FIL_NULL if out of space */ -static __attribute__((nonnull(1,5), warn_unused_result)) -ulint -btr_page_alloc_low( -/*===============*/ +@return new allocated block, x-latched; NULL if out of space */ +UNIV_INTERN +buf_block_t* +btr_page_alloc( +/*===========*/ dict_index_t* index, /*!< in: index */ ulint hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - in which the page should be - initialized (may be the same - as mtr), or NULL if it should - not be initialized (the page - at hint was previously freed - in mtr) */ + mtr_t* mtr) /*!< in: mtr */ { fseg_header_t* seg_header; page_t* root; + buf_block_t* new_block; + ulint new_page_no; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } root = btr_root_get(index, mtr); @@ -942,42 +941,8 @@ btr_page_alloc_low( reservation for free extents, and thus we know that a page can be allocated: */ - return(fseg_alloc_free_page_general( - seg_header, hint_page_no, file_direction, - TRUE, mtr, init_mtr)); -} - -/**************************************************************//** -Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! -@return new allocated block, x-latched; NULL if out of space */ -UNIV_INTERN -buf_block_t* -btr_page_alloc( -/*===========*/ - dict_index_t* index, /*!< in: index */ - ulint hint_page_no, /*!< in: hint of a good page */ - byte file_direction, /*!< in: direction where a possible - page split is made */ - ulint level, /*!< in: level where the page is placed - in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ -{ - buf_block_t* new_block; - ulint new_page_no; - - if (dict_index_is_ibuf(index)) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } - - new_page_no = btr_page_alloc_low( - index, hint_page_no, file_direction, level, mtr, init_mtr); - + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); if (new_page_no == FIL_NULL) { return(NULL); @@ -985,16 +950,9 @@ btr_page_alloc( new_block = buf_page_get(dict_index_get_space(index), dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, init_mtr); + new_page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); - if (mtr->freed_clust_leaf) { - mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(!mtr_memo_contains(mtr, new_block, - MTR_MEMO_FREE_CLUST_LEAF)); - } - - ut_ad(btr_freed_leaves_validate(mtr)); return(new_block); } @@ -1107,15 +1065,6 @@ btr_page_free_low( fseg_free_page(seg_header, buf_block_get_space(block), buf_block_get_page_no(block), mtr); - - /* The page was marked free in the allocation bitmap, but it - should remain buffer-fixed until mtr_commit(mtr) or until it - is explicitly freed from the mini-transaction. */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* TODO: Discard any operations on the page from the redo log - and remove the block from the flush list and the buffer pool. - This would free up buffer pool earlier and reduce writes to - both the tablespace and the redo log. */ } /**************************************************************//** @@ -1129,140 +1078,13 @@ btr_page_free( buf_block_t* block, /*!< in: block to be freed, x-latched */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page = buf_block_get_frame(block); - ulint level = btr_page_get_level(page, mtr); + ulint level; + + level = btr_page_get_level(buf_block_get_frame(block), mtr); - ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX); btr_page_free_low(index, block, level, mtr); - - /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - - if (level == 0 && dict_index_is_clust(index)) { - /* We may have to call btr_mark_freed_leaves() to - temporarily mark the block nonfree for invoking - btr_store_big_rec_extern_fields_func() after an - update. Remember that the block was freed. */ - mtr->freed_clust_leaf = TRUE; - mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF); - } - - ut_ad(btr_freed_leaves_validate(mtr)); } -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ -{ - /* This is loosely based on mtr_memo_release(). */ - - ulint offset; - - ut_ad(dict_index_is_clust(index)); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - if (!mtr->freed_clust_leaf) { - return; - } - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(buf_block_get_space(block) - == dict_index_get_space(index)); - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - - if (nonfree) { - /* Allocate the same page again. */ - ulint page_no; - page_no = btr_page_alloc_low( - index, buf_block_get_page_no(block), - FSP_NO_DIR, 0, mtr, NULL); - ut_a(page_no == buf_block_get_page_no(block)); - } else { - /* Assert that the page is allocated and free it. */ - btr_page_free_low(index, block, 0, mtr); - } - } - - ut_ad(btr_freed_leaves_validate(mtr)); -} - -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ -{ - ulint offset; - - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - const mtr_memo_slot_t* slot; - const buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - ut_a(mtr->freed_clust_leaf); - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(page_is_leaf(buf_block_get_frame(block))); - } - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - /**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1987,7 +1809,7 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2458,7 +2280,7 @@ btr_attach_half_pages( /*==================*/ dict_index_t* index, /*!< in: the index tree */ buf_block_t* block, /*!< in/out: page to be split */ - const rec_t* split_rec, /*!< in: first record on upper + rec_t* split_rec, /*!< in: first record on upper half page */ buf_block_t* new_block, /*!< in/out: the new half page */ ulint direction, /*!< in: FSP_UP or FSP_DOWN */ @@ -2723,7 +2545,7 @@ func_start: /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr, mtr); + btr_page_get_level(page, mtr), mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, @@ -3173,16 +2995,15 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); + btr_cur_compress_if_useful(&cursor, mtr); } } /*************************************************************//** If page is the only on its level, this function moves its records to the -father page, thus reducing the tree height. -@return father block */ +father page, thus reducing the tree height. */ static -buf_block_t* +void btr_lift_page_up( /*=============*/ dict_index_t* index, /*!< in: index tree */ @@ -3299,8 +3120,6 @@ btr_lift_page_up( } ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_block, mtr)); - - return(father_block); } /*************************************************************//** @@ -3317,13 +3136,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; ulint space; @@ -3341,14 +3158,12 @@ btr_compress( ulint* offsets; ulint data_size; ulint n_recs; - ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; block = btr_cur_get_block(cursor); page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); - ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -3369,10 +3184,6 @@ btr_compress( offsets = btr_page_get_father_block(NULL, heap, index, block, mtr, &father_cursor); - if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); - } - /* Decide the page to which we try to merge and which will inherit the locks */ @@ -3399,9 +3210,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - - merge_block = btr_lift_page_up(index, block, mtr); - goto func_exit; + btr_lift_page_up(index, block, mtr); + mem_heap_free(heap); + return(TRUE); } n_recs = page_get_n_recs(page); @@ -3483,10 +3294,6 @@ err_exit: btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); - - if (adjust) { - nth_rec += page_rec_get_n_recs_before(orig_pred); - } } else { rec_t* orig_succ; #ifdef UNIV_BTR_DEBUG @@ -3551,6 +3358,7 @@ err_exit: } btr_blob_dbg_remove(page, index, "btr_compress"); + mem_heap_free(heap); if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) { /* Update the free bits of the B-tree page in the @@ -3602,16 +3410,6 @@ err_exit: btr_page_free(index, block, mtr); ut_ad(btr_check_node_ptr(index, merge_block, mtr)); -func_exit: - mem_heap_free(heap); - - if (adjust) { - btr_cur_position( - index, - page_rec_get_nth(merge_block->frame, nth_rec), - merge_block, cursor); - } - return(TRUE); } diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 3021bb71929..f63ca20ef24 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1985,6 +1985,7 @@ btr_cur_optimistic_update( ulint old_rec_size; dtuple_t* new_entry; roll_ptr_t roll_ptr; + trx_t* trx; mem_heap_t* heap; ulint i; ulint n_ext; @@ -2001,10 +2002,9 @@ btr_cur_optimistic_update( heap = mem_heap_create(1024); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_is_recv(thr_get_trx(thr))); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#ifdef UNIV_BLOB_NULL_DEBUG + ut_a(!rec_offs_any_null_extern(rec, offsets)); +#endif /* UNIV_BLOB_NULL_DEBUG */ #ifdef UNIV_DEBUG if (btr_cur_print_record_ops && thr) { @@ -2127,11 +2127,13 @@ any_extern: page_cur_move_to_prev(page_cursor); + trx = thr_get_trx(thr); + if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, - thr_get_trx(thr)->id); + trx->id); } /* There are no externally stored columns in new_entry */ @@ -2217,9 +2219,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -2358,7 +2358,7 @@ btr_cur_pessimistic_update( record to be inserted: we have to remember which fields were such */ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec)); - ut_ad(rec_offs_validate(rec, index, offsets)); + offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap); n_ext += btr_push_update_extern_fields(new_entry, update, *heap); if (UNIV_LIKELY_NULL(page_zip)) { @@ -2381,10 +2381,6 @@ make_external: err = DB_TOO_BIG_RECORD; goto return_after_reservations; } - - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); } /* Store state of explicit locks on rec on the page infimum record, @@ -2412,8 +2408,6 @@ make_external: rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr); if (rec) { - page_cursor->rec = rec; - lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor), rec, block); @@ -2427,10 +2421,7 @@ make_external: rec, index, offsets, mtr); } - btr_cur_compress_if_useful( - cursor, - big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), - mtr); + btr_cur_compress_if_useful(cursor, mtr); if (page_zip && !dict_index_is_clust(index) && page_is_leaf(page)) { @@ -2450,21 +2441,6 @@ make_external: } } - if (big_rec_vec) { - ut_ad(page_is_leaf(page)); - ut_ad(dict_index_is_clust(index)); - ut_ad(flags & BTR_KEEP_POS_FLAG); - - /* btr_page_split_and_insert() in - btr_cur_pessimistic_insert() invokes - mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). - We must keep the index->lock when we created a - big_rec, so that row_upd_clust_rec() can store the - big_rec in the same mini-transaction. */ - - mtr_x_lock(dict_index_get_lock(index), mtr); - } - /* Was the record to be updated positioned as the first user record on its page? */ was_first = page_cur_is_before_first(page_cursor); @@ -2480,7 +2456,6 @@ make_external: ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); - page_cursor->rec = rec; if (dict_index_is_sec_or_ibuf(index)) { /* Update PAGE_MAX_TRX_ID in the index page header. @@ -2915,12 +2890,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + btr_cur_t* cursor, /*!< in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2929,7 +2902,7 @@ btr_cur_compress_if_useful( MTR_MEMO_PAGE_X_FIX)); return(btr_cur_compress_recommendation(cursor, mtr) - && btr_compress(cursor, adjust, mtr)); + && btr_compress(cursor, mtr)); } /*******************************************************//** @@ -3171,7 +3144,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); + ret = btr_cur_compress_if_useful(cursor, mtr); } if (n_extents > 0) { @@ -4160,9 +4133,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ - #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -4171,11 +4141,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + { ulint rec_page_no; byte* field_ref; @@ -4194,9 +4162,6 @@ btr_store_big_rec_extern_fields_func( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); - ut_ad(local_mtr); - ut_ad(!alloc_mtr || alloc_mtr == local_mtr); - ut_ad(!update_in_place || alloc_mtr); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -4212,25 +4177,6 @@ btr_store_big_rec_extern_fields_func( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); - if (alloc_mtr) { - /* Because alloc_mtr will be committed after - mtr, it is possible that the tablespace has been - extended when the B-tree record was updated or - inserted, or it will be extended while allocating - pages for big_rec. - - TODO: In mtr (not alloc_mtr), write a redo log record - about extending the tablespace to its current size, - and remember the current size. Whenever the tablespace - grows as pages are allocated, write further redo log - records to mtr. (Currently tablespace extension is not - covered by the redo log. If it were, the record would - only be written to alloc_mtr, which is committed after - mtr.) */ - } else { - alloc_mtr = &mtr; - } - if (UNIV_LIKELY_NULL(page_zip)) { int err; @@ -4307,7 +4253,7 @@ btr_store_big_rec_extern_fields_func( } block = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, alloc_mtr, &mtr); + FSP_NO_DIR, 0, &mtr); if (UNIV_UNLIKELY(block == NULL)) { mtr_commit(&mtr); @@ -4434,15 +4380,11 @@ btr_store_big_rec_extern_fields_func( goto next_zip_page; } - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); if (err == Z_STREAM_END) { mach_write_to_4(field_ref @@ -4476,8 +4418,7 @@ btr_store_big_rec_extern_fields_func( page_zip_write_blob_ptr( page_zip, rec, index, offsets, - big_rec_vec->fields[i].field_no, - alloc_mtr); + big_rec_vec->fields[i].field_no, &mtr); next_zip_page: prev_page_no = page_no; @@ -4522,23 +4463,19 @@ next_zip_page: extern_len -= store_len; - if (alloc_mtr == &mtr) { - rec_block = buf_page_get( - space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level( - rec_block, - SYNC_NO_ORDER_CHECK); - } + rec_block = buf_page_get(space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level(rec_block, + SYNC_NO_ORDER_CHECK); mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { btr_blob_dbg_add_blob( @@ -4548,19 +4485,18 @@ next_zip_page: mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, - space_id, MLOG_4BYTES, - alloc_mtr); + space_id, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO, - page_no, MLOG_4BYTES, - alloc_mtr); + page_no, + MLOG_4BYTES, &mtr); mlog_write_ulint(field_ref + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, - alloc_mtr); + MLOG_4BYTES, &mtr); } prev_page_no = page_no; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index e0b9e979970..33b4cd40215 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1715,6 +1715,31 @@ buf_page_set_accessed_make_young( } } +/********************************************************************//** +Resets the check_index_page_at_flush field of a page if found in the buffer +pool. */ +UNIV_INTERN +void +buf_reset_check_index_page_at_flush( +/*================================*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: page number */ +{ + buf_block_t* block; + buf_pool_t* buf_pool = buf_pool_get(space, offset); + + buf_pool_mutex_enter(buf_pool); + + block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); + + if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); + block->check_index_page_at_flush = FALSE; + } + + buf_pool_mutex_exit(buf_pool); +} + /********************************************************************//** Returns the current state of is_hashed of a page. FALSE if the page is not in the pool. NOTE that this operation does not fix the page in the diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 96d29e8ae32..3f09732a676 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -311,9 +311,8 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - UNIV_COLD __attribute__((nonnull)); + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr); /*!< in: mtr */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -326,20 +325,14 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in/out: segment inode */ + fseg_inode_t* seg_inode, /*!< in: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ - __attribute__((warn_unused_result, nonnull(3,6))); + mtr_t* mtr); /*!< in: mtr handle */ #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -707,18 +700,17 @@ list, if not free limit == space size. This adding is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -UNIV_INLINE __attribute__((nonnull, warn_unused_result)) +UNIV_INLINE xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header, /*!< in/out: space header, x-latched - in mtr */ - ulint space, /*!< in: space id */ - ulint offset, /*!< in: page offset; if equal - to the free limit, we try to - add new extents to the space - free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page offset; + if equal to the free limit, + we try to add new extents to + the space free list */ + mtr_t* mtr) /*!< in: mtr handle */ { ulint limit; ulint size; @@ -726,9 +718,11 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; + ut_ad(mtr); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX) + || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -778,7 +772,7 @@ is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -static __attribute__((nonnull, warn_unused_result)) +static xdes_t* xdes_get_descriptor( /*================*/ @@ -787,7 +781,7 @@ xdes_get_descriptor( or 0 for uncompressed pages */ ulint offset, /*!< in: page offset; if equal to the free limit, we try to add new extents to the space free list */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr handle */ { buf_block_t* block; fsp_header_t* sp_header; @@ -1165,14 +1159,14 @@ fsp_header_get_tablespace_size(void) Tries to extend a single-table tablespace so that a page would fit in the data file. @return TRUE if success */ -static UNIV_COLD __attribute__((nonnull, warn_unused_result)) +static ibool fsp_try_extend_data_file_with_pages( /*================================*/ ulint space, /*!< in: space */ ulint page_no, /*!< in: page number */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ibool success; ulint actual_size; @@ -1197,7 +1191,7 @@ fsp_try_extend_data_file_with_pages( /***********************************************************************//** Tries to extend the last data file of a tablespace if it is auto-extending. @return FALSE if not auto-extending */ -static UNIV_COLD __attribute__((nonnull)) +static ibool fsp_try_extend_data_file( /*=====================*/ @@ -1207,8 +1201,8 @@ fsp_try_extend_data_file( the actual file size rounded down to megabyte */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + fsp_header_t* header, /*!< in: space header */ + mtr_t* mtr) /*!< in: mtr */ { ulint size; ulint zip_size; @@ -1344,7 +1338,7 @@ fsp_fill_free_list( then we do not allocate more extents */ ulint space, /*!< in: space */ fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + mtr_t* mtr) /*!< in: mtr */ { ulint limit; ulint size; @@ -1542,47 +1536,10 @@ fsp_alloc_free_extent( return(descr); } -/**********************************************************************//** -Allocates a single free page from a space. */ -static __attribute__((nonnull)) -void -fsp_alloc_from_free_frag( -/*=====================*/ - fsp_header_t* header, /*!< in/out: tablespace header */ - xdes_t* descr, /*!< in/out: extent descriptor */ - ulint bit, /*!< in: slot to allocate in the extent */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - ulint frag_n_used; - - ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); - xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } -} - /**********************************************************************//** Allocates a single free page from a space. The page is marked as used. @return the page offset, FIL_NULL if no page could be allocated */ -static __attribute__((nonnull, warn_unused_result)) +static ulint fsp_alloc_free_page( /*================*/ @@ -1590,22 +1547,19 @@ fsp_alloc_free_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint hint, /*!< in: hint of which page would be desirable */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr) */ + mtr_t* mtr) /*!< in: mtr handle */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; buf_block_t* block; ulint free; + ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); - ut_ad(init_mtr); header = fsp_get_space_header(space, zip_size, mtr); @@ -1687,19 +1641,38 @@ fsp_alloc_free_page( } } - fsp_alloc_from_free_frag(header, descr, free, mtr); + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, zip_size, init_mtr); + buf_page_create(space, page_no, zip_size, mtr); - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr); + block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); + fsp_init_file_page(block, mtr); return(page_no); } @@ -1935,7 +1908,7 @@ fsp_alloc_seg_inode_page( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); + page_no = fsp_alloc_free_page(space, zip_size, 0, mtr); if (page_no == FIL_NULL) { @@ -2347,7 +2320,7 @@ fseg_create_general( if (page == 0) { page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr, mtr); + inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { @@ -2596,19 +2569,14 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in/out: segment inode */ + fseg_inode_t* seg_inode, /*!< in: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr) /*!< in: mtr handle */ { fsp_header_t* space_header; ulint space_size; @@ -2619,6 +2587,7 @@ fseg_alloc_free_page_low( ulint ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ + ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2640,8 +2609,6 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ - ut_a(init_mtr); - /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2652,20 +2619,15 @@ fseg_alloc_free_page_low( && mach_read_from_8(descr + XDES_ID) == seg_id && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { -take_hinted_page: + /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; - /* Skip the check for extending the tablespace. If the - page hint were not within the size of the tablespace, - we would have got (descr == NULL) above and reset the hint. */ - goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if (xdes_get_state(descr, mtr) == XDES_FREE - && (!init_mtr - || ((reserved - used < reserved / FSEG_FILLFACTOR) - && used >= FSEG_FRAG_LIMIT))) { + } else if ((xdes_get_state(descr, mtr) == XDES_FREE) + && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && (used >= FSEG_FRAG_LIMIT)) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2683,20 +2645,8 @@ take_hinted_page: /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, zip_size, hint + FSP_EXTENT_SIZE, mtr); - goto take_hinted_page; - /*-----------------------------------------------------------*/ - } else if (!init_mtr) { - ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - fsp_alloc_from_free_frag(space_header, descr, - hint % FSP_EXTENT_SIZE, mtr); ret_page = hint; - ret_descr = NULL; - - /* Put the page in the fragment page array of the segment */ - n = fseg_find_free_frag_page_slot(seg_inode, mtr); - ut_a(n != FIL_NULL); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); - goto got_hinted_page; + /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2755,10 +2705,11 @@ take_hinted_page: } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, zip_size, hint, - mtr, init_mtr); + ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr); ret_descr = NULL; + frag_page_allocated = TRUE; + if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2768,10 +2719,6 @@ take_hinted_page: fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } - - /* fsp_alloc_free_page() invoked fsp_init_file_page() - already. */ - return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2819,34 +2766,26 @@ take_hinted_page: } } -got_hinted_page: - { + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ buf_block_t* block; ulint zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - block = buf_page_create(space, ret_page, zip_size, block_mtr); + block = buf_page_create(space, ret_page, zip_size, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size, ret_page, RW_X_LATCH, - block_mtr))) { + mtr))) { ut_error; } - if (init_mtr) { - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, init_mtr); - } - } + /* The prior contents of the page should be ignored */ + fsp_init_file_page(block, mtr); - /* ret_descr == NULL if the block was allocated from free_frag - (XDES_FREE_FRAG) */ - if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2859,6 +2798,8 @@ got_hinted_page: fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr); } + buf_reset_check_index_page_at_flush(space, ret_page); + return(ret_page); } @@ -2871,7 +2812,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in/out: segment header */ + fseg_header_t* seg_header,/*!< in: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -2883,11 +2824,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction handle */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /*!< in: mtr handle */ { fseg_inode_t* inode; ulint space; @@ -2929,8 +2866,7 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, - mtr, init_mtr); + inode, hint, direction, mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2938,6 +2874,28 @@ fseg_alloc_free_page_general( return(page_no); } +/**********************************************************************//** +Allocates a single free page from a segment. This function implements +the intelligent allocation strategy which tries to minimize file space +fragmentation. +@return allocated page offset, FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header,/*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction,/*!< in: if the new page is needed because + of an index page split, and records are + inserted there in order, into which + direction they go alphabetically: FSP_DOWN, + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + return(fseg_alloc_free_page_general(seg_header, hint, direction, + FALSE, mtr)); +} + /**********************************************************************//** Checks that we have at least 2 frag pages free in the first extent of a single-table tablespace, and they are also physically initialized to the data diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 3dfd98ceb08..71e772388a0 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -499,14 +499,11 @@ UNIV_INTERN ibool btr_compress( /*=========*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr); /*!< in: mtr */ /*************************************************************//** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot @@ -568,12 +565,7 @@ btr_page_alloc( page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr, /*!< in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /*!< in/out: mini-transaction - for x-latching and initializing - the page */ - __attribute__((nonnull, warn_unused_result)); + mtr_t* mtr); /*!< in: mtr */ /**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -596,33 +588,6 @@ btr_page_free_low( buf_block_t* block, /*!< in: block to be freed, x-latched */ ulint level, /*!< in: page level */ mtr_t* mtr); /*!< in: mtr */ -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ -UNIV_INTERN -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /*!< in/out: clustered index */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ - UNIV_COLD __attribute__((nonnull)); -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -@see btr_mark_freed_leaves() -@return TRUE */ -UNIV_INTERN -ibool -btr_freed_leaves_validate( -/*======================*/ - mtr_t* mtr) /*!< in: mini-transaction */ - __attribute__((nonnull, warn_unused_result)); -#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /*************************************************************//** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 26ed766dbd4..be918439f59 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -36,9 +36,6 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ -#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() - must keep cursor position when - moving columns to big_rec */ #ifndef UNIV_HOTBACKUP #include "que0types.h" @@ -313,9 +310,7 @@ btr_cur_pessimistic_update( /*=======================*/ ulint flags, /*!< in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /*!< in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /*!< in: cursor on the record to update */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to be stored externally by the caller, or NULL */ @@ -369,13 +364,10 @@ UNIV_INTERN ibool btr_cur_compress_if_useful( /*=======================*/ - btr_cur_t* cursor, /*!< in/out: cursor on the page to compress; + btr_cur_t* cursor, /*!< in: cursor on the page to compress; cursor does not stay valid if compression occurs */ - ibool adjust, /*!< in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); + mtr_t* mtr); /*!< in: mtr */ /*******************************************************//** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, @@ -518,8 +510,6 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ - const big_rec_t*big_rec_vec, /*!< in: vector containing fields - to be stored externally */ #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -528,12 +518,9 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ - __attribute__((nonnull(1,2,3,4,5), warn_unused_result)); + const big_rec_t*big_rec_vec) /*!< in: vector containing fields + to be stored externally */ + __attribute__((nonnull)); /** Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. @@ -542,22 +529,21 @@ file segment of the index tree. @param index in: clustered index; MUST be X-latched by mtr @param b in/out: block containing rec; MUST be X-latched by mtr @param rec in/out: clustered index record -@param offs in: rec_get_offsets(rec, index); +@param offsets in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not be adjusted -@param big in: vector containing fields to be stored externally @param mtr in: mini-transaction that holds x-latch on index and b @param upd in: TRUE if the record is updated in place (not delete+insert) -@param rmtr in/out: in updates, the mini-transaction that holds rec +@param big in: vector containing fields to be stored externally @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ #ifdef UNIV_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) #elif defined UNIV_BLOB_LIGHT_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) #else -# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr) +# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) #endif /*******************************************************************//** diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic index c833b3e8572..280583f6ccf 100644 --- a/storage/innobase/include/btr0cur.ic +++ b/storage/innobase/include/btr0cur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -139,7 +139,7 @@ btr_cur_compress_recommendation( btr_cur_t* cursor, /*!< in: btr cursor */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page; + page_t* page; ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 03b80fce2e8..ccebb69a4fe 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -491,6 +491,15 @@ buf_page_peek( /*==========*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: page number */ +/********************************************************************//** +Resets the check_index_page_at_flush field of a page if found in the buffer +pool. */ +UNIV_INTERN +void +buf_reset_check_index_page_at_flush( +/*================================*/ + ulint space, /*!< in: space id */ + ulint offset);/*!< in: page number */ #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. @@ -600,31 +609,6 @@ buf_block_get_modify_clock( #else /* !UNIV_HOTBACKUP */ # define buf_block_modify_clock_inc(block) ((void) 0) #endif /* !UNIV_HOTBACKUP */ -/*******************************************************************//** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc_func( -/*=======================*/ -#ifdef UNIV_SYNC_DEBUG - const char* file, /*!< in: file name */ - ulint line, /*!< in: line */ -#endif /* UNIV_SYNC_DEBUG */ - buf_block_t* block) /*!< in/out: block to bufferfix */ - __attribute__((nonnull)); -#ifdef UNIV_SYNC_DEBUG -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) -#else /* UNIV_SYNC_DEBUG */ -/** Increments the bufferfix count. -@param b in/out: block to bufferfix -@param f in: file name where requested -@param l in: line number where requested */ -# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) -#endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 0e80ce55e57..b65b5133c15 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -944,6 +944,19 @@ buf_block_buf_fix_inc_func( block->page.buf_fix_count++; } +#ifdef UNIV_SYNC_DEBUG +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) +#else /* UNIV_SYNC_DEBUG */ +/** Increments the bufferfix count. +@param b in/out: block to bufferfix +@param f in: file name where requested +@param l in: line number where requested */ +# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) +#endif /* UNIV_SYNC_DEBUG */ /*******************************************************************//** Decrements the bufferfix count. */ @@ -1194,7 +1207,7 @@ buf_block_dbg_add_level( where we have acquired latch */ ulint level) /*!< in: latching order level */ { - sync_thread_add_level(&block->lock, level, FALSE); + sync_thread_add_level(&block->lock, level); } #endif /* UNIV_SYNC_DEBUG */ /********************************************************************//** diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 2221380c9a2..7abd3914eda 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -176,18 +176,19 @@ fseg_n_reserved_pages( Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space fragmentation. -@param[in/out] seg_header segment header -@param[in] hint hint of which page would be desirable -@param[in] direction if the new page is needed because +@return the allocated page offset FIL_NULL if no page could be allocated */ +UNIV_INTERN +ulint +fseg_alloc_free_page( +/*=================*/ + fseg_header_t* seg_header, /*!< in: segment header */ + ulint hint, /*!< in: hint of which page would be desirable */ + byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR -@param[in/out] mtr mini-transaction -@return the allocated page offset FIL_NULL if no page could be allocated */ -#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \ - fseg_alloc_free_page_general(seg_header, hint, direction, \ - FALSE, mtr, mtr) + FSP_UP, FSP_NO_DIR */ + mtr_t* mtr); /*!< in: mtr handle */ /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -197,7 +198,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in/out: segment header */ + fseg_header_t* seg_header,/*!< in: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -209,12 +210,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ - __attribute__((warn_unused_result, nonnull(1,5))); + mtr_t* mtr); /*!< in: mtr handle */ /**********************************************************************//** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 185a0953231..7f608546cc2 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -53,8 +53,6 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 -/** The mini-transaction freed a clustered index leaf page. */ -#define MTR_MEMO_FREE_CLUST_LEAF 57 /** @name Log item types The log items are declared 'byte' so that the compiler can warn if val @@ -370,14 +368,11 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ - unsigned inside_ibuf:1; + ibool inside_ibuf; /*!< TRUE if inside ibuf changes */ - unsigned modifications:1; - /*!< TRUE if the mini-transaction - modified buffer pool pages */ - unsigned freed_clust_leaf:1; - /*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF - was logged in the mini-transaction */ + ibool modifications; + /* TRUE if the mtr made modifications to + buffer pool pages */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 3541f359338..1db4a4bd735 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. 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 @@ -43,9 +43,8 @@ mtr_start( dyn_array_create(&(mtr->log)); mtr->log_mode = MTR_LOG_ALL; - mtr->inside_ibuf = FALSE; mtr->modifications = FALSE; - mtr->freed_clust_leaf = FALSE; + mtr->inside_ibuf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); @@ -67,8 +66,7 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); + ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); diff --git a/storage/innobase/include/page0cur.ic b/storage/innobase/include/page0cur.ic index 81474fa35f5..3520677dfb3 100644 --- a/storage/innobase/include/page0cur.ic +++ b/storage/innobase/include/page0cur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -27,8 +27,6 @@ Created 10/4/1994 Heikki Tuuri #include "buf0types.h" #ifdef UNIV_DEBUG -# include "rem0cmp.h" - /*********************************************************//** Gets pointer to the page frame where the cursor is positioned. @return page */ @@ -270,7 +268,6 @@ page_cur_tuple_insert( index, rec, offsets, mtr); } - ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, offsets)); mem_heap_free(heap); return(rec); } diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index ad1445b3935..6a82e820312 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -281,42 +281,16 @@ page_get_supremum_offset( const page_t* page); /*!< in: page which must have record(s) */ #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) - /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*< in: page */ - ulint nth) /*!< in: nth record */ - __attribute__((nonnull, warn_unused_result)); - -#ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. +Returns the middle record of record list. If there are an even number +of records in the list, returns the first record of upper half-list. @return middle record */ -UNIV_INLINE +UNIV_INTERN rec_t* page_get_middle_rec( /*================*/ - page_t* page) /*!< in: page */ - __attribute__((nonnull, warn_unused_result)); + page_t* page); /*!< in: page */ +#ifndef UNIV_HOTBACKUP /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an @@ -371,7 +345,6 @@ page_get_n_recs( /***************************************************************//** Returns the number of records before the given record in chain. The number includes infimum and supremum records. -This is the inverse function of page_rec_get_nth(). @return number of records */ UNIV_INTERN ulint diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index c1a0ce73982..115cee64f8b 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -419,37 +419,7 @@ page_rec_is_infimum( return(page_rec_is_infimum_low(page_offset(rec))); } -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ -UNIV_INLINE -rec_t* -page_rec_get_nth( -/*=============*/ - page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ -{ - return((rec_t*) page_rec_get_nth_const(page, nth)); -} - #ifndef UNIV_HOTBACKUP -/************************************************************//** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. -@return middle record */ -UNIV_INLINE -rec_t* -page_get_middle_rec( -/*================*/ - page_t* page) /*!< in: page */ -{ - ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; - - return(page_rec_get_nth(page, middle)); -} - /*************************************************************//** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 46914d13c7f..10b74d18c13 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -480,7 +480,7 @@ ulint rec_offs_any_extern( /*================*/ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG /******************************************************//** Determine if the offsets are for a record containing null BLOB pointers. @return first field containing a null BLOB pointer, or NULL if none found */ @@ -491,7 +491,7 @@ rec_offs_any_null_extern( const rec_t* rec, /*!< in: record */ const ulint* offsets) /*!< in: rec_get_offsets(rec) */ __attribute__((nonnull, warn_unused_result)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. @return nonzero if externally stored */ diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index ebda6105bf1..dc8ed515c30 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -1088,7 +1088,7 @@ rec_offs_any_extern( return(UNIV_UNLIKELY(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL)); } -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG /******************************************************//** Determine if the offsets are for a record containing null BLOB pointers. @return first field containing a null BLOB pointer, or NULL if none found */ @@ -1124,7 +1124,7 @@ rec_offs_any_null_extern( return(NULL); } -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ /******************************************************//** Returns nonzero if the extern bit is set in nth field of rec. diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index 5d15677ccce..2ffd9fdafb5 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -603,16 +603,16 @@ rw_lock_x_unlock_direct( ut_ad((lock->lock_word % X_LOCK_DECR) == 0); +#ifdef UNIV_SYNC_DEBUG + rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); +#endif + if (lock->lock_word == 0) { lock->recursive = FALSE; UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); } -#ifdef UNIV_SYNC_DEBUG - rw_lock_remove_debug_info(lock, 0, RW_LOCK_EX); -#endif - lock->lock_word += X_LOCK_DECR; ut_ad(!lock->waiters); diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index f6b8897522f..d9dea0aa63d 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -400,10 +400,8 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level, /*!< in: level in the latching order; if + ulint level); /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ - ibool relock) /*!< in: TRUE if re-entering an x-lock */ - __attribute__((nonnull)); /******************************************************************//** Removes a latch from the thread level array if it is found there. @return TRUE if found in the array; it is no error if the latch is diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index cb175c2c234..e86cd4402bf 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2009, Sun Microsystems, Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -185,6 +186,8 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column debugging without UNIV_DEBUG */ +#define UNIV_BLOB_NULL_DEBUG /* Enable deep off-page + column debugging */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ #define UNIV_DEBUG_LOCK_VALIDATE /* Enable diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index fde87cb3cd3..08234609ff0 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2009, Innobase Oy. 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 @@ -64,11 +64,12 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); +#ifdef UNIV_DEBUG } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY - || type == MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type == MTR_MEMO_MODIFY); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); +#endif /* UNIV_DEBUG */ } else { rw_lock_x_unlock((rw_lock_t*)object); } diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index b8c492328e8..936762b986a 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2009, Innobase Oy. 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 @@ -1180,15 +1180,14 @@ page_cur_insert_rec_zip_reorg( /* Before trying to reorganize the page, store the number of preceding records on the page. */ pos = page_rec_get_n_recs_before(rec); - ut_ad(pos > 0); if (page_zip_reorganize(block, index, mtr)) { /* The page was reorganized: Find rec by seeking to pos, and update *current_rec. */ - if (pos > 1) { - rec = page_rec_get_nth(page, pos - 1); - } else { - rec = page + PAGE_NEW_INFIMUM; + rec = page + PAGE_NEW_INFIMUM; + + while (--pos) { + rec = page + rec_get_next_offs(rec, TRUE); } *current_rec = rec; @@ -1284,12 +1283,6 @@ page_cur_insert_rec_zip( insert_rec = page_cur_insert_rec_zip_reorg( current_rec, block, index, insert_rec, page, page_zip, mtr); -#ifdef UNIV_DEBUG - if (insert_rec) { - rec_offs_make_valid( - insert_rec, index, offsets); - } -#endif /* UNIV_DEBUG */ } return(insert_rec); diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 1c74a1d5cab..6064d028ae1 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. 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 @@ -1465,54 +1465,55 @@ page_dir_balance_slot( } } +#ifndef UNIV_HOTBACKUP /************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). -@return nth record */ +Returns the middle record of the record list. If there are an even number +of records in the list, returns the first record of the upper half-list. +@return middle record */ UNIV_INTERN -const rec_t* -page_rec_get_nth_const( -/*===================*/ - const page_t* page, /*!< in: page */ - ulint nth) /*!< in: nth record */ +rec_t* +page_get_middle_rec( +/*================*/ + page_t* page) /*!< in: page */ { - const page_dir_slot_t* slot; + page_dir_slot_t* slot; + ulint middle; ulint i; ulint n_owned; - const rec_t* rec; + ulint count; + rec_t* rec; - ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); + /* This many records we must leave behind */ + middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; + + count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (n_owned > nth) { + if (count + n_owned > middle) { break; } else { - nth -= n_owned; + count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); - rec = page_dir_slot_get_rec(slot); + rec = (rec_t*) page_dir_slot_get_rec(slot); + rec = page_rec_get_next(rec); - if (page_is_comp(page)) { - do { - rec = page_rec_get_next_low(rec, TRUE); - ut_ad(rec); - } while (nth--); - } else { - do { - rec = page_rec_get_next_low(rec, FALSE); - ut_ad(rec); - } while (nth--); + /* There are now count records behind rec */ + + for (i = 0; i < middle - count; i++) { + rec = page_rec_get_next(rec); } return(rec); } +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** Returns the number of records before the given record in chain. @@ -1574,7 +1575,6 @@ page_rec_get_n_recs_before( n--; ut_ad(n >= 0); - ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); return((ulint) n); } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 5f10a763fc4..2925feb2904 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. 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 @@ -348,9 +348,9 @@ row_ins_clust_index_entry_by_modify( return(DB_LOCK_TABLE_FULL); } - err = btr_cur_pessimistic_update( - BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update(0, cursor, + heap, big_rec, update, + 0, thr, mtr); } return(err); @@ -1976,7 +1976,6 @@ row_ins_index_entry_low( ulint modify = 0; /* remove warning */ rec_t* insert_rec; rec_t* rec; - ulint* offsets; ulint err; ulint n_unique; big_rec_t* big_rec = NULL; @@ -2084,51 +2083,6 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &heap, &big_rec, entry, thr, &mtr); - - if (big_rec) { - ut_a(err == DB_SUCCESS); - /* Write out the externally stored - columns, but allocate the pages and - write the pointers using the - mini-transaction of the record update. - If any pages were freed in the update, - temporarily mark them allocated so - that off-page columns will not - overwrite them. We must do this, - because we will write the redo log for - the BLOB writes before writing the - redo log for the record update. Thus, - redo log application at crash recovery - will see BLOBs being written to free pages. */ - - btr_mark_freed_leaves(index, &mtr, TRUE); - - rec = btr_cur_get_rec(&cursor); - offsets = rec_get_offsets( - rec, index, NULL, - ULINT_UNDEFINED, &heap); - - err = btr_store_big_rec_extern_fields( - index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, - FALSE, &mtr); - /* If writing big_rec fails (for - example, because of DB_OUT_OF_FILE_SPACE), - the record will be corrupted. Even if - we did not update any externally - stored columns, our update could cause - the record to grow so that a - non-updated column was selected for - external storage. This non-update - would not have been written to the - undo log, and thus the record cannot - be rolled back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again - in order to avoid a leak. */ - btr_mark_freed_leaves(index, &mtr, FALSE); - goto stored_big_rec; - } } else { ut_ad(!n_ext); err = row_ins_sec_index_entry_by_modify( @@ -2157,6 +2111,8 @@ function_exit: mtr_commit(&mtr); if (UNIV_LIKELY_NULL(big_rec)) { + rec_t* rec; + ulint* offsets; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2168,9 +2124,8 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, big_rec, &mtr, FALSE, NULL); + rec, offsets, &mtr, FALSE, big_rec); -stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); } else { @@ -2443,7 +2398,7 @@ row_ins( node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); - /* Skip corrupted secondary index and its entry */ + /* Skip corrupted secondar index and its entry */ while (node->index && dict_index_is_corrupted(node->index)) { node->index = dict_table_get_next_index(node->index); diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 8892c8dc289..20fd475343e 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -233,7 +233,6 @@ row_build( ut_ad(index && rec && heap); ut_ad(dict_index_is_clust(index)); - ut_ad(!mutex_own(&kernel_mutex)); if (!offsets) { offsets = rec_get_offsets(rec, index, offsets_, @@ -242,22 +241,13 @@ row_build( ut_ad(rec_offs_validate(rec, index, offsets)); } -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - if (rec_offs_any_null_extern(rec, offsets)) { - /* This condition can occur during crash recovery - before trx_rollback_active() has completed execution. - - This condition is possible if the server crashed - during an insert or update-by-delete-and-insert before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the freshly inserted clustered index - record. */ - ut_a(trx_assert_recovered( - row_get_rec_trx_id(rec, index, offsets))); - ut_a(trx_undo_roll_ptr_is_insert( - row_get_rec_roll_ptr(rec, index, offsets))); - } -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#if 0 && defined UNIV_BLOB_NULL_DEBUG + /* This one can fail in trx_rollback_active() if + the server crashed during an insert before the + btr_store_big_rec_extern_fields() did mtr_commit() + all BLOB pointers to the clustered index record. */ + ut_a(!rec_offs_any_null_extern(rec, offsets)); +#endif /* 0 && UNIV_BLOB_NULL_DEBUG */ if (type != ROW_COPY_POINTERS) { /* Take a copy of rec to heap */ @@ -442,10 +432,10 @@ row_rec_to_index_entry( rec = rec_copy(buf, rec, offsets); /* Avoid a debug assertion in rec_offs_validate(). */ rec_offs_make_valid(rec, index, offsets); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG } else { ut_a(!rec_offs_any_null_extern(rec, offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ } entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 2401fc88553..765233c8dab 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. 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 @@ -1999,46 +1999,28 @@ row_upd_clust_rec( ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update( - BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, - &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); - if (big_rec) { + err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, + &heap, &big_rec, node->update, + node->cmpl_info, thr, mtr); + mtr_commit(mtr); + + if (err == DB_SUCCESS && big_rec) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); - ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns, but - allocate the pages and write the pointers using the - mini-transaction of the record update. If any pages - were freed in the update, temporarily mark them - allocated so that off-page columns will not overwrite - them. We must do this, because we write the redo log - for the BLOB writes before writing the redo log for - the record update. */ + mtr_start(mtr); - btr_mark_freed_leaves(index, mtr, TRUE); + ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr, TRUE, mtr); - /* If writing big_rec fails (for example, because of - DB_OUT_OF_FILE_SPACE), the record will be corrupted. - Even if we did not update any externally stored - columns, our update could cause the record to grow so - that a non-updated column was selected for external - storage. This non-update would not have been written - to the undo log, and thus the record cannot be rolled - back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again in order to avoid a leak. */ - btr_mark_freed_leaves(index, mtr, FALSE); + mtr, TRUE, big_rec); + mtr_commit(mtr); } - mtr_commit(mtr); - if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } diff --git a/storage/innobase/row/row0vers.c b/storage/innobase/row/row0vers.c index abd065ce1ff..5fd7d082194 100644 --- a/storage/innobase/row/row0vers.c +++ b/storage/innobase/row/row0vers.c @@ -550,10 +550,10 @@ row_vers_build_for_consistent_read( /* The view already sees this version: we can copy it to in_heap and return */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern( version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); @@ -588,9 +588,9 @@ row_vers_build_for_consistent_read( *offsets = rec_get_offsets(prev_version, index, *offsets, ULINT_UNDEFINED, offset_heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(prev_version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ trx_id = row_get_rec_trx_id(prev_version, index, *offsets); @@ -691,9 +691,9 @@ row_vers_build_for_semi_consistent_read( /* We found a version that belongs to a committed transaction: return it. */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ if (rec == version) { *old_vers = rec; @@ -752,9 +752,9 @@ row_vers_build_for_semi_consistent_read( version = prev_version; *offsets = rec_get_offsets(version, index, *offsets, ULINT_UNDEFINED, offset_heap); -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +#ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(version, *offsets)); -#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +#endif /* UNIV_BLOB_NULL_DEBUG */ }/* for (;;) */ if (heap) { diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 5b72e0afdf4..397d505df50 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -782,9 +782,7 @@ rw_lock_add_debug_info( rw_lock_debug_mutex_exit(); if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) { - sync_thread_add_level(lock, lock->level, - lock_type == RW_LOCK_EX - && lock->lock_word < 0); + sync_thread_add_level(lock, lock->level); } } diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index af6e3f0e275..8ea57b8655c 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -690,7 +690,7 @@ mutex_set_debug_info( ut_ad(mutex); ut_ad(file_name); - sync_thread_add_level(mutex, mutex->level, FALSE); + sync_thread_add_level(mutex, mutex->level); mutex->file_name = file_name; mutex->line = line; @@ -1133,9 +1133,8 @@ void sync_thread_add_level( /*==================*/ void* latch, /*!< in: pointer to a mutex or an rw-lock */ - ulint level, /*!< in: level in the latching order; if + ulint level) /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ - ibool relock) /*!< in: TRUE if re-entering an x-lock */ { ulint i; sync_level_t* slot; @@ -1186,10 +1185,6 @@ sync_thread_add_level( array = thread_slot->levels; - if (relock) { - goto levels_ok; - } - /* NOTE that there is a problem with _NODE and _LEAF levels: if the B-tree height changes, then a leaf can change to an internal node or the other way around. We do not know at present if this can cause @@ -1366,7 +1361,6 @@ sync_thread_add_level( ut_error; } -levels_ok: if (array->next_free == ULINT_UNDEFINED) { ut_a(array->n_elems < array->max_elems); diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index ad209110e60..0bf41780fcc 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -1621,9 +1621,9 @@ trx_undo_prev_version_build( return(DB_ERROR); } -# if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG +# ifdef UNIV_BLOB_NULL_DEBUG ut_a(!rec_offs_any_null_extern(rec, offsets)); -# endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ +# endif /* UNIV_BLOB_NULL_DEBUG */ if (row_upd_changes_field_size_or_external(index, offsets, update)) { ulint n_ext; diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 805fdcee242..dae0637f72c 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2009, Innobase Oy. 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 @@ -918,7 +918,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr, mtr); + TRUE, mtr); fil_space_release_free_extents(undo->space, n_reserved); From da454e2ee16b0f5d70cfe0496af8b0f1a67f3d58 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 30 Sep 2011 15:58:02 +0300 Subject: [PATCH 129/143] bug#bug11747416 post-push fixes to correct file name print out. --- .../suite/rpl/r/rpl_cant_read_event_incident.result | 2 +- mysql-test/suite/rpl/r/rpl_log_pos.result | 2 +- .../suite/rpl/r/rpl_manual_change_index_file.result | 2 +- mysql-test/suite/rpl/r/rpl_packet.result | 2 +- sql/sql_repl.cc | 11 ++++++++--- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result index f8ff9594dfa..1bee6f2ec1a 100644 --- a/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result +++ b/mysql-test/suite/rpl/r/rpl_cant_read_event_incident.result @@ -11,7 +11,7 @@ reset slave; start slave; include/wait_for_slave_param.inc [Last_IO_Errno] Last_IO_Errno = '1236' -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the last event was read from ./master-bin.000001 at 316, the last byte read was read from ./master-bin.000001 at 335.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the last event was read from 'master-bin.000001' at 316, the last byte read was read from 'master-bin.000001' at 335.'' reset master; stop slave; reset slave; diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 753eb86be44..5e9c096d773 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; the last event was read from ./master-bin.000001 at 75, the last byte read was read from ./master-bin.000001 at 94.'' +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; the last event was read from 'master-bin.000001' at 75, the last byte read was read from 'master-bin.000001' at 94.'' 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_manual_change_index_file.result b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result index 479f84ef648..41101da98f8 100644 --- a/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result +++ b/mysql-test/suite/rpl/r/rpl_manual_change_index_file.result @@ -5,7 +5,7 @@ CREATE TABLE t1(c1 INT); FLUSH LOGS; call mtr.add_suppression('Got fatal error 1236 from master when reading data from binary log: .*could not find next log'); include/wait_for_slave_io_error.inc [errno=1236] -Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from ./master-bin.000002 at 237, the last byte read was read from ./master-bin.000002 at 237.'' +Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the last event was read from 'master-bin.000002' at 237, the last byte read was read from 'master-bin.000002' at 237.'' CREATE TABLE t2(c1 INT); FLUSH LOGS; CREATE TABLE t3(c1 INT); diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 03b2e3131e1..a11fc16123d 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -37,7 +37,7 @@ 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; the last event was read from ./master-bin.000001 at 463, the last byte read was read from ./master-bin.000001 at 482.'' +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; the last event was read from 'master-bin.000001' at 463, the last byte read was read from 'master-bin.000001' at 482.'' STOP SLAVE; RESET SLAVE; RESET MASTER; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c0d9432c71a..a37e8700e4f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -447,7 +447,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, String* packet = &thd->packet; int error; const char *errmsg = "Unknown error"; - const char *fmt= "%s; the last event was read from %s at %s, the last byte read was read from %s at %s."; + const char *fmt= "%s; the last event was read from '%s' at %s, the last byte read was read from '%s' at %s."; char llbuff1[22], llbuff2[22]; char error_text[MAX_SLAVE_ERRMSG]; // to be send to slave via my_message() NET* net = &thd->net; @@ -1012,13 +1012,18 @@ end: err: thd_proc_info(thd, "Waiting to finalize termination"); if (my_errno == ER_MASTER_FATAL_ERROR_READING_BINLOG && my_b_inited(&log)) + { /* detailing the fatal error message with coordinates of the last position read. */ + char b_start[FN_REFLEN], b_end[FN_REFLEN]; + fn_format(b_start, coord->file_name, "", "", MY_REPLACE_DIR); + fn_format(b_end, log_file_name, "", "", MY_REPLACE_DIR); my_snprintf(error_text, sizeof(error_text), fmt, errmsg, - coord->file_name, (llstr(coord->pos, llbuff1), llbuff1), - log_file_name, (llstr(my_b_tell(&log), llbuff2), llbuff2)); + b_start, (llstr(coord->pos, llbuff1), llbuff1), + b_end, (llstr(my_b_tell(&log), llbuff2), llbuff2)); + } else strcpy(error_text, errmsg); end_io_cache(&log); From 37de3c2c0bcb642bb71e7f842c26208b5bfd7dd9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 30 Sep 2011 15:25:19 +0200 Subject: [PATCH 130/143] 12956584 followup fix for mysqltest run_query_stmt() might use disable_xxx vars after calling handle_no_error But handle_no_error() hes reverted any ONCE settings Fix is to take revert_properties() out of handle_no_error() --- client/mysqltest.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 1661385162c..915c6e4d495 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5364,6 +5364,7 @@ do_handle_error: var_set_errno(0); handle_no_error(command); + revert_properties(); return 1; /* Connected */ } @@ -7319,6 +7320,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, /* If we come here the query is both executed and read successfully */ handle_no_error(command); + revert_properties(); end: @@ -7514,8 +7516,6 @@ void handle_no_error(struct st_command *command) die("query '%s' succeeded - should have failed with sqlstate %s...", command->query, command->expected_errors.err[0].code.sqlstate); } - - revert_properties(); DBUG_VOID_RETURN; } @@ -7546,9 +7546,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); - /* Remember disable_result_log since handle_no_error() may reset it */ - my_bool dis_res= disable_result_log; - /* Init a new stmt if it's not already one created for this connection */ @@ -7644,7 +7641,7 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, /* If we got here the statement was both executed and read successfully */ handle_no_error(command); - if (!dis_res) + if (!disable_result_log) { /* Not all statements creates a result set. If there is one we can @@ -7720,7 +7717,7 @@ end: dynstr_free(&ds_prepare_warnings); dynstr_free(&ds_execute_warnings); } - + revert_properties(); /* Close the statement if - no reconnect, need new prepare */ if (mysql->reconnect) From c01c37a7ef37ac9e407005e48d173ae61d9b2c72 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Mon, 3 Oct 2011 09:31:55 +0200 Subject: [PATCH 131/143] Bug#13030056 62533: UNITTEST/MYSYS/MY_ATOMIC-T.C DOES NOT COMPILE ON MACOSX LION The problem was that on optimized builds, the wrong code was generated for my_atomic_add64 if a variable argument was optimized away as a constant. This patch fixes the problem by making the variable volatile. Another workaround is to specify architecture explicitly using e.g. CFLAGS/CXXFLAGS= "-m64". No test case added. --- unittest/mysys/my_atomic-t.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c index 89588a05405..ae9bb6903f5 100644 --- a/unittest/mysys/my_atomic-t.c +++ b/unittest/mysys/my_atomic-t.c @@ -164,7 +164,14 @@ void do_tests() test_concurrently("my_atomic_cas32", test_atomic_cas, THREADS, CYCLES); { - int64 b=0x1000200030004000LL; + /* + If b is not volatile, the wrong assembly code is generated on OSX Lion + as the variable is optimized away as a constant. + See Bug#62533 / Bug#13030056. + Another workaround is to specify architecture explicitly using e.g. + CFLAGS/CXXFLAGS= "-m64". + */ + volatile int64 b=0x1000200030004000LL; a64=0; my_atomic_add64(&a64, b); ok(a64==b, "add64"); From 0122a138e4b8da24fc0f943fad9f610ad5b6f4d2 Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Mon, 3 Oct 2011 16:05:52 +0530 Subject: [PATCH 132/143] BUG#11758262 BUG#13043055: Fix for commit_1innodb failure on pb2. Background: as status increment differs for an unsafe statement when logged in stmt and row format, mtr throws a content mismatch error. Fix: call p_verify_status_increment with different arguments for loging format as stmt and row/mixed and disable query log. --- mysql-test/include/commit.inc | 26 ++++++++++++++++++++++++-- mysql-test/r/commit_1innodb.result | 2 -- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc index e84ad0f940d..fdb9ef1f563 100644 --- a/mysql-test/include/commit.inc +++ b/mysql-test/include/commit.inc @@ -524,9 +524,31 @@ call p_verify_status_increment(2, 2, 2, 2); --disable_warnings update ignore t1 set a=2 where a=1; --enable_warnings -call p_verify_status_increment(2, 2, 1, 0); +if (`select @@binlog_format = 'STATEMENT'`) +{ + --disable_query_log + call p_verify_status_increment(2, 2, 1, 0); + --enable_query_log +} +if (`select @@binlog_format != 'STATEMENT'`) +{ + --disable_query_log + call p_verify_status_increment(1, 0, 1, 0); + --enable_query_log +} commit; -call p_verify_status_increment(2, 2, 1, 0); +if (`select @@binlog_format = 'STATEMENT'`) +{ + --disable_query_log + call p_verify_status_increment(2, 2, 1, 0); + --enable_query_log +} +if (`select @@binlog_format != 'STATEMENT'`) +{ + --disable_query_log + call p_verify_status_increment(1, 0, 1, 0); + --enable_query_log +} --echo # --echo # Create a stored function that modifies a --echo # non-transactional table. Demonstrate that changes in diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index fb1552b6c28..3e3d75f66e4 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -549,11 +549,9 @@ SUCCESS # 15. Read-write statement: UPDATE IGNORE, change 0 rows. # update ignore t1 set a=2 where a=1; -call p_verify_status_increment(2, 2, 1, 0); SUCCESS commit; -call p_verify_status_increment(2, 2, 1, 0); SUCCESS # From 996614178bc138285570eff95f085a774d1bedb8 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 3 Oct 2011 13:16:40 +0200 Subject: [PATCH 133/143] mtr: print which suites are used, unless explicit test names --- mysql-test/mysql-test-run.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 715276a221d..d278c36f033 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -385,6 +385,7 @@ sub main { } } } + mtr_report("Using suites: $opt_suites") unless @opt_cases; init_timers(); From 968e4363fd2efd4bbb86aefbc84f7398ec54b1f7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 3 Oct 2011 13:41:59 +0200 Subject: [PATCH 134/143] backporting 11766169, fixing 13034450 --- mysql-test/lib/mtr_cases.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 3dcd99f235f..9b5608241a3 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -222,8 +222,11 @@ sub collect_test_cases ($$$) { sub split_testname { my ($test_name)= @_; - # Get rid of directory part and split name on .'s - my @parts= split(/\./, basename($test_name)); + # If .test file name is used, get rid of directory part + $test_name= basename($test_name) if $test_name =~ /\.test$/; + + # Now split name on .'s + my @parts= split(/\./, $test_name); if (@parts == 1){ # Only testname given, ex: alias From 4836c66d3cf8f32491d8d256d6cc03a9339716a2 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 4 Oct 2011 15:58:19 +0200 Subject: [PATCH 135/143] Fix bug#11886309: RPM UPGRADE OF MYSQL ADVANCED GPL TO MYSQL SERVER ADVANCED DOES NOT WORK Change the RPM spec file so that each RPM "obsoletes" the corresponding RPMs of all (other) configurations, so a "server" RPM of any configuration can replace the "server" RPM of any other configuration on a "rpm -U". --- support-files/mysql.spec.sh | 73 ++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 28f2b0f773a..ee0211fd3e0 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -170,9 +170,11 @@ documentation and the manual for more information. %package server Summary: MySQL: a very fast and reliable SQL database server Group: Applications/Databases -Requires: coreutils grep procps /usr/sbin/useradd /usr/sbin/groupadd /sbin/chkconfig -Provides: msqlormysql mysql-server mysql MySQL -Obsoletes: MySQL mysql mysql-server +Requires: coreutils grep procps /usr/sbin/useradd /usr/sbin/groupadd /sbin/chkconfig +Provides: msqlormysql mysql MySQL mysql-server MySQL-server +Obsoletes: mysql MySQL mysql-server MySQL-server +Obsoletes: MySQL-server-classic MySQL-server-community MySQL-server-enterprise +Obsoletes: MySQL-server-advanced MySQL-server-advanced-gpl MySQL-server-enterprise-gpl %description server The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, @@ -202,10 +204,12 @@ package "MySQL-client" as well! # ------------------------------------------------------------------------------ %package client -Summary: MySQL - Client -Group: Applications/Databases -Obsoletes: mysql-client -Provides: mysql-client +Summary: MySQL - Client +Group: Applications/Databases +Provides: mysql-client MySQL-client +Obsoletes: mysql-client MySQL-client +Obsoletes: MySQL-client-classic MySQL-client-community MySQL-client-enterprise +Obsoletes: MySQL-client-advanced MySQL-client-advanced-gpl MySQL-client-enterprise-gpl %description client This package contains the standard MySQL clients and administration tools. @@ -266,11 +270,14 @@ They should be used with caution. # ------------------------------------------------------------------------------ %package test -Requires: %{name}-client perl -Summary: MySQL - Test suite -Group: Applications/Databases -Provides: mysql-test -Obsoletes: mysql-bench mysql-test +Summary: MySQL - Test suite +Group: Applications/Databases +Requires: %{name}-client perl +Provides: mysql-test MySQL-test +Obsoletes: mysql-test MySQL-test +Obsoletes: mysql-bench MySQL-bench +Obsoletes: MySQL-test-classic MySQL-test-community MySQL-test-enterprise +Obsoletes: MySQL-test-advanced MySQL-test-advanced-gpl MySQL-test-enterprise-gpl AutoReqProv: no %description test @@ -281,10 +288,12 @@ This package contains the MySQL regression test suite. # ------------------------------------------------------------------------------ %package devel -Summary: MySQL - Development header files and libraries -Group: Applications/Databases -Provides: mysql-devel -Obsoletes: mysql-devel +Summary: MySQL - Development header files and libraries +Group: Applications/Databases +Provides: mysql-devel MySQL-devel +Obsoletes: mysql-devel MySQL-devel +Obsoletes: MySQL-devel-classic MySQL-devel-community MySQL-devel-enterprise +Obsoletes: MySQL-devel-advanced MySQL-devel-advanced-gpl MySQL-devel-enterprise-gpl %description devel This package contains the development header files and libraries @@ -295,8 +304,14 @@ necessary to develop MySQL client applications. # ------------------------------------------------------------------------------ %package shared -Summary: MySQL - Shared libraries -Group: Applications/Databases +Summary: MySQL - Shared libraries +Group: Applications/Databases +Provides: mysql-shared MySQL-shared +Obsoletes: mysql-shared MySQL-shared-standard MySQL-shared-pro +Obsoletes: MySQL-shared-pro-cert MySQL-shared-pro-gpl +Obsoletes: MySQL-shared-pro-gpl-cert MySQL-shared +Obsoletes: MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise +Obsoletes: MySQL-shared-advanced MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl %description shared This package contains the shared libraries (*.so*) which certain @@ -307,10 +322,14 @@ languages and applications need to dynamically load and use MySQL. %if %{EMBEDDED_BUILD} %package embedded -Requires: %{name}-devel -Summary: MySQL - embedded library -Group: Applications/Databases -Obsoletes: mysql-embedded +Summary: MySQL - Embedded library +Group: Applications/Databases +Requires: %{name}-devel +Provides: mysql-embedded MySQL-embedded +Obsoletes: mysql-embedded MySQL-embedded +Obsoletes: MySQL-embedded-pro +Obsoletes: MySQL-embedded-classic MySQL-embedded-community MySQL-embedded-enterprise +Obsoletes: MySQL-embedded-advanced MySQL-embedded-advanced-gpl MySQL-embedded-enterprise-gpl %description embedded This package contains the MySQL server as an embedded library. @@ -1172,6 +1191,16 @@ fi # merging BK trees) ############################################################################## %changelog +* Wed Sep 14 2011 Joerg Bruehe + +- Let the RPM capabilities ("obsoletes" etc) ensure that an upgrade may replace + the RPMs of any configuration (of the current or the preceding release series) + by the new ones. This is done by not using the implicitly generated capabilities + (which include the configuration name) and relying on more generic ones which + just list the function ("server", "client", ...). + The implicit generation cannot be prevented, so all these capabilities must be + explicitly listed in "Obsoletes:" + * Fri Aug 19 2011 Joerg Bruehe - Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" From c6d47e6e01e9f9dcb0ea1d7b3582136b65face32 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Oct 2011 09:21:47 -0500 Subject: [PATCH 136/143] Bug#12980094 and Bug#13034534 Bug 12980094 - ASSERTION IN INNODB DETECTED IN RQG_PARTITION_DDL Bug 13034534 - RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT All access to struct rw_lock_debug_struct must be protected by rw_lock_debug_mutex_enter(). --- storage/innobase/include/sync0rw.h | 3 ++- storage/innobase/sync/sync0rw.c | 10 +++++++--- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/include/sync0rw.h | 3 ++- storage/innodb_plugin/sync/sync0rw.c | 4 ++++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index dd898557d6e..6bd81623ad2 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -484,7 +484,8 @@ struct rw_lock_struct { #define RW_LOCK_MAGIC_N 22643 #ifdef UNIV_SYNC_DEBUG -/* The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /* The thread id of the thread which diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 089e87a8a5c..d82baaace69 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -732,7 +732,7 @@ rw_lock_own( ut_ad(lock); ut_ad(rw_lock_validate(lock)); - mutex_enter(&(lock->mutex)); + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); @@ -742,7 +742,7 @@ rw_lock_own( && (info->pass == 0) && (info->lock_type == lock_type)) { - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); /* Found! */ return(TRUE); @@ -750,7 +750,7 @@ rw_lock_own( info = UT_LIST_GET_NEXT(list, info); } - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); return(FALSE); } @@ -830,11 +830,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } mutex_exit(&(lock->mutex)); @@ -870,11 +872,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 171f1edd7ba..379d37fdedd 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-29 The InnoDB Team + + * sync/sync0rw.c: + Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT + 2011-09-20 The InnoDB Team * row/row0purge.c: diff --git a/storage/innodb_plugin/include/sync0rw.h b/storage/innodb_plugin/include/sync0rw.h index 47f7dbfe0eb..40be1396a4c 100644 --- a/storage/innodb_plugin/include/sync0rw.h +++ b/storage/innodb_plugin/include/sync0rw.h @@ -564,7 +564,8 @@ struct rw_lock_struct { }; #ifdef UNIV_SYNC_DEBUG -/** The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /*!< The thread id of the thread which diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 3df2b4e9bbd..0127c12a5e4 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -928,11 +928,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_exit(&(lock->mutex)); @@ -976,11 +978,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } From 96c2c18e4f6b484aea7cbce5646c1280661f73a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 4 Oct 2011 21:01:40 +0300 Subject: [PATCH 137/143] Correct the ChangeLog --- storage/innodb_plugin/ChangeLog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 379d37fdedd..cdf8e8351a8 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,7 +1,8 @@ -2011-09-29 The InnoDB Team +2011-10-04 The InnoDB Team - * sync/sync0rw.c: - Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT + * include/sync0rw.h, sync/sync0rw.c: + Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR + RW_LOCK_DEBUG_PRINT 2011-09-20 The InnoDB Team From 16c919527fbedf373d7cbc34415b87cacea18993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 5 Oct 2011 12:01:47 +0300 Subject: [PATCH 138/143] Add InnoDB UNIV_SYNC_DEBUG assertions to rw-lock code. rw_lock_x_lock_func(): Assert that the thread is not already holding the lock in a conflicting mode (RW_LOCK_SHARED). rw_lock_s_lock_func(): Assert that the thread is not already holding the lock in a conflicting mode (RW_LOCK_EX). --- storage/innobase/include/sync0rw.ic | 1 + storage/innobase/sync/sync0rw.c | 3 +++ storage/innodb_plugin/include/sync0rw.ic | 1 + storage/innodb_plugin/sync/sync0rw.c | 3 +++ 4 files changed, 8 insertions(+) diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index eea639f26f4..2a674f00262 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -238,6 +238,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ mutex_enter(rw_lock_get_mutex(lock)); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index d82baaace69..05ea8ff0fe9 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -476,6 +476,9 @@ rw_lock_x_lock_func( ulint i; /* spin round count */ ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ lock_loop: /* Acquire the mutex protecting the rw-lock fields */ diff --git a/storage/innodb_plugin/include/sync0rw.ic b/storage/innodb_plugin/include/sync0rw.ic index 485a63a1b18..5eb3d017eca 100644 --- a/storage/innodb_plugin/include/sync0rw.ic +++ b/storage/innodb_plugin/include/sync0rw.ic @@ -406,6 +406,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 0127c12a5e4..bc060319246 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -612,6 +612,9 @@ rw_lock_x_lock_func( ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ i = 0; From 14dc91ff83001809fc40380ab22fc4e606f611de Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 5 Oct 2011 13:28:20 +0400 Subject: [PATCH 139/143] Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT Problematic query: insert ignore into `t1_federated` (`c1`) select `c1` from `t1_local` a where not exists (select 1 from `t1_federated` b where a.c1 = b.c1); When this query is killed in another connection it could lead to crash. The problem is follwing: An attempt to obtain table statistics for subselect table in killed query fails with an error. So JOIN::optimize() for subquery is failed but it does not prevent further subquery evaluation. At the first subquery execution JOIN::optimize() is called (see subselect_single_select_engine::exec()) and fails with an error. 'executed' flag is set to TRUE and it prevents further subquery evaluation. At the second call JOIN::optimize() does not happen as 'JOIN::optimized' is TRUE and in case of uncacheable subquery the 'executed' flag is set to FALSE before subquery evaluation. So we loose 'optimize stage' error indication (see subselect_single_select_engine::exec()). In other words 'executed' flag is used for two purposes, for error indication at JOIN::optimize() stage and for an indication of subquery execution. And it seems it's wrong as the flag could be reset. mysql-test/r/error_simulation.result: test case mysql-test/t/error_simulation.test: test case sql/item_subselect.cc: added new flag subselect_single_select_engine::optimize_error which is used for error detection which could happen at optimize stage. sql/item_subselect.h: added new flag subselect_single_select_engine::optimize_error sql/sql_select.cc: test case --- mysql-test/r/error_simulation.result | 13 +++++++++++++ mysql-test/t/error_simulation.test | 14 ++++++++++++++ sql/item_subselect.cc | 13 ++++++++++--- sql/item_subselect.h | 1 + sql/sql_select.cc | 10 ++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/error_simulation.result b/mysql-test/r/error_simulation.result index b6b79cb596b..f1835186787 100644 --- a/mysql-test/r/error_simulation.result +++ b/mysql-test/r/error_simulation.result @@ -83,5 +83,18 @@ a a b filler SET SESSION debug = DEFAULT; DROP TABLE t1, t2; # +# Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT +# +CREATE TABLE t1(f1 INT, KEY(f1)); +CREATE TABLE t2(f1 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SET SESSION debug='d,bug11747970_simulate_error'; +INSERT IGNORE INTO t2 SELECT f1 FROM t1 a WHERE NOT EXISTS (SELECT 1 FROM t2 b WHERE a.f1 = b.f1); +Warnings: +Error 1105 Unknown error +SET SESSION debug = DEFAULT; +DROP TABLE t1,t2; +# # End of 5.1 tests # diff --git a/mysql-test/t/error_simulation.test b/mysql-test/t/error_simulation.test index f6edacfaa29..95ec2c5b21d 100644 --- a/mysql-test/t/error_simulation.test +++ b/mysql-test/t/error_simulation.test @@ -89,6 +89,20 @@ SET SESSION debug = DEFAULT; DROP TABLE t1, t2; + +--echo # +--echo # Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT +--echo # +CREATE TABLE t1(f1 INT, KEY(f1)); +CREATE TABLE t2(f1 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SET SESSION debug='d,bug11747970_simulate_error'; +INSERT IGNORE INTO t2 SELECT f1 FROM t1 a WHERE NOT EXISTS (SELECT 1 FROM t2 b WHERE a.f1 = b.f1); +SET SESSION debug = DEFAULT; +DROP TABLE t1,t2; + + --echo # --echo # End of 5.1 tests --echo # diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 10dd6c93717..2fa0178ed8c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1679,7 +1679,7 @@ subselect_single_select_engine(st_select_lex *select, select_subselect *result_arg, Item_subselect *item_arg) :subselect_engine(item_arg, result_arg), - prepared(0), optimized(0), executed(0), + prepared(0), optimized(0), executed(0), optimize_error(0), select_lex(select), join(0) { select_lex->master_unit()->item= item_arg; @@ -1689,7 +1689,7 @@ subselect_single_select_engine(st_select_lex *select, void subselect_single_select_engine::cleanup() { DBUG_ENTER("subselect_single_select_engine::cleanup"); - prepared= optimized= executed= 0; + prepared= optimized= executed= optimize_error= 0; join= 0; result->cleanup(); DBUG_VOID_RETURN; @@ -1885,6 +1885,10 @@ int join_read_next_same_or_null(READ_RECORD *info); int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); + + if (optimize_error) + DBUG_RETURN(1); + char const *save_where= thd->where; SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; @@ -1892,12 +1896,15 @@ int subselect_single_select_engine::exec() { SELECT_LEX_UNIT *unit= select_lex->master_unit(); + DBUG_EXECUTE_IF("bug11747970_simulate_error", + DBUG_SET("+d,bug11747970_raise_error");); + optimized= 1; unit->set_limit(unit->global_parameters); if (join->optimize()) { thd->where= save_where; - executed= 1; + optimize_error= 1; thd->lex->current_select= save_select; DBUG_RETURN(join->error ? join->error : 1); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 74bbec626c1..65b415b44e9 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -419,6 +419,7 @@ class subselect_single_select_engine: public subselect_engine my_bool prepared; /* simple subselect is prepared */ my_bool optimized; /* simple subselect is optimized */ my_bool executed; /* simple subselect is executed */ + my_bool optimize_error; ///< simple subselect optimization failed st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 516c9c37473..bf0cd7c9db8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2677,6 +2677,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + + DBUG_EXECUTE_IF("bug11747970_raise_error", + { + if (!error) + { + my_error(ER_UNKNOWN_ERROR, MYF(0)); + goto error; + } + }); + if (error) { table->file->print_error(error, MYF(0)); From 83f3aa148b18398f0d209e756c221c29e8fab46b Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 5 Oct 2011 15:16:20 +0200 Subject: [PATCH 140/143] Silly mistake in gdb output: replaced print with resfile_print, but the latter only takes one argument, duh! Fixed by concatenating the args (replace , with .) --- mysql-test/lib/My/CoreDump.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/My/CoreDump.pm b/mysql-test/lib/My/CoreDump.pm index b0c4a1337d8..419a0e7f39f 100644 --- a/mysql-test/lib/My/CoreDump.pm +++ b/mysql-test/lib/My/CoreDump.pm @@ -81,7 +81,7 @@ sub _gdb { return if $? >> 8; return unless $gdb_output; - resfile_print < Date: Thu, 6 Oct 2011 14:13:23 +0200 Subject: [PATCH 141/143] Bug#12912112 MYSQL_CLIENT_TEST FAILS ON TEST_TRUNCATION Sun Studio 12 has an error when calculating the compile-time length of a constant character string. The error is only present when building an optimized 32-bits version, using the -xbuiltin=(%all) compiler flag. During compilation, the compiler recognizes the use of the strlen() function used on a constant string. It optimizes the strlen and replaces it with the actual length of the string. This optimization seems to calculate the length wrongly in this particular case. Replacing the "const char *" with a "const char []" solves the problem. --- tests/mysql_client_test.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 14a60f0e857..4050f18c674 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13445,7 +13445,10 @@ static void test_truncation() ")"; rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); myquery(rc); - stmt_text= "insert into t1 VALUES (" + + { + const char insert_text[]= + "insert into t1 VALUES (" "-10, " /* i8 */ "200, " /* ui8 */ "32000, " /* i16 */ @@ -13461,8 +13464,9 @@ static void test_truncation() "'12345.67 ', " /* tx_1 */ "'12345.67abc'" /* ch_2 */ ")"; - rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); - myquery(rc); + rc= mysql_real_query(mysql, insert_text, strlen(insert_text)); + myquery(rc); + } stmt_text= "select i8 c1, i8 c2, ui8 c3, i16_1 c4, ui16 c5, " " i16 c6, ui16 c7, i32 c8, i32_1 c9, i32_1 c10, " From 22fdbd40d4daae0ba7fed2edc04348f1026c7951 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Mon, 10 Oct 2011 14:03:29 +0200 Subject: [PATCH 142/143] Test "file_contents" failed in non-community RPMs on SuSE because the search pattern for the "INFO_*" files was not general enough: Fixed. --- mysql-test/t/file_contents.test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/t/file_contents.test b/mysql-test/t/file_contents.test index 33cd65fb2b4..965f6c3b363 100644 --- a/mysql-test/t/file_contents.test +++ b/mysql-test/t/file_contents.test @@ -15,9 +15,9 @@ if ($dir_bin =~ m|/usr/|) { # RPM package $dir_docs = $dir_bin; $dir_docs =~ s|/lib|/share/doc|; - if(-d "$dir_docs/packages/MySQL-server") { - # SuSE - $dir_docs = "$dir_docs/packages/MySQL-server"; + if(-d "$dir_docs/packages") { + # SuSE: "packages/" in the documentation path + $dir_docs = glob "$dir_docs/packages/MySQL-server*"; } else { # RedHat: version number in directory name $dir_docs = glob "$dir_docs/MySQL-server*"; @@ -25,9 +25,9 @@ if ($dir_bin =~ m|/usr/|) { } elsif ($dir_bin =~ m|/usr$|) { # RPM build during development $dir_docs = "$dir_bin/share/doc"; - if(-d "$dir_docs/packages/MySQL-server") { - # SuSE - $dir_docs = "$dir_docs/packages/MySQL-server"; + if(-d "$dir_docs/packages") { + # SuSE: "packages/" in the documentation path + $dir_docs = glob "$dir_docs/packages/MySQL-server*"; } else { # RedHat: version number in directory name $dir_docs = glob "$dir_docs/MySQL-server*"; From 73db2a1504188611c3348e1bd55d181aea6ab533 Mon Sep 17 00:00:00 2001 From: Vinay Fisrekar Date: Wed, 12 Oct 2011 10:10:52 +0530 Subject: [PATCH 143/143] bug#11766457 - adjusting/modifying the the tests as tests were failing if system time zone is set differently. --- mysql-test/suite/engines/funcs/r/de_calendar_range.result | 2 ++ .../in_calendar_2_unique_constraints_duplicate_update.result | 2 ++ .../r/in_calendar_pk_constraint_duplicate_update.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_error.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_ignore.result | 2 ++ .../r/in_calendar_unique_constraint_duplicate_update.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_error.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_ignore.result | 2 ++ ...ulticolumn_calendar_pk_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_error.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_ignore.result | 2 ++ ...column_calendar_unique_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_unique_constraint_error.result | 2 ++ .../in_multicolumn_calendar_unique_constraint_ignore.result | 2 ++ ..._multicolumn_number_pk_constraint_duplicate_update.result | 2 ++ mysql-test/suite/engines/funcs/r/up_calendar_range.result | 2 ++ mysql-test/suite/engines/funcs/t/de_calendar_range.test | 5 ++++- .../t/in_calendar_2_unique_constraints_duplicate_update.test | 4 ++++ .../funcs/t/in_calendar_pk_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_error.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_ignore.test | 4 ++++ .../t/in_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_unique_constraint_error.test | 5 ++++- .../funcs/t/in_calendar_unique_constraint_ignore.test | 5 ++++- ..._multicolumn_calendar_pk_constraint_duplicate_update.test | 4 ++++ .../funcs/t/in_multicolumn_calendar_pk_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_pk_constraint_ignore.test | 5 ++++- ...ticolumn_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_ignore.test | 4 ++++ ...in_multicolumn_number_pk_constraint_duplicate_update.test | 4 ++++ mysql-test/suite/engines/funcs/t/up_calendar_range.test | 5 ++++- 32 files changed, 96 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/engines/funcs/r/de_calendar_range.result b/mysql-test/suite/engines/funcs/r/de_calendar_range.result index 904b14c06b5..07543e0c8c4 100644 --- a/mysql-test/suite/engines/funcs/r/de_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/de_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -89,3 +90,4 @@ c1 2007-02-16 12:10:34 2007-02-17 13:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result index 7479cf3ea0b..9c56e23574d 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -128,3 +129,4 @@ c1 c2 c3 2003 2001 2000 2004 2000 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result index 763e9f564c6..47355681eae 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result index 154c44426bc..5c4307158fa 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result index 6c395c5f6b9..9f6a205530c 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result index 58802aab0b2..5469527b762 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -81,3 +82,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result index 3b40a2f57ab..edad4bb218d 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result index 84f626d3347..4d7cadac70c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result index f34b39ec1b4..31f7db1dc9a 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -139,3 +140,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/up_calendar_range.result b/mysql-test/suite/engines/funcs/r/up_calendar_range.result index 7185fc3c6ee..dbd6e2cf8a6 100644 --- a/mysql-test/suite/engines/funcs/r/up_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/up_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -104,3 +105,4 @@ c1 2007-02-13 09:09:33 2007-02-14 10:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/de_calendar_range.test b/mysql-test/suite/engines/funcs/t/de_calendar_range.test index c1e191fdd97..6e3f1915e9a 100644 --- a/mysql-test/suite/engines/funcs/t/de_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/de_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -45,4 +47,5 @@ SELECT * FROM t1 ORDER BY c1; DELETE FROM t1 WHERE c1 <= ADDTIME(NOW(),'2 02:01:01'); SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test index 8c6f960b60d..5ae519abdc8 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -70,4 +72,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(2000,2000,2000) ON DUPLICATE KEY UPDATE c3=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test index 65c7c34f907..fdfb6edb139 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test index 36a8ef3a0a7..f65c705031b 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test index 36a8ef3a0a7..bac71b99a97 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,6 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test index 20da85f5b66..e6235e77603 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test index 73b8c3d0775..f9d101d8327 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test index 91e4f8faef9..a4e96a7ccc3 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT IGNORE INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +#restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test index a7648a55128..12307232d64 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test index 13575722c1f..3d455bcb5d8 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test index 916b0c527eb..9cbafd3b8d0 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test index b43ff52abe3..e313f29edfb 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT IGNORE INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test index 71848c1ac38..df4a194a2cf 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/up_calendar_range.test b/mysql-test/suite/engines/funcs/t/up_calendar_range.test index 9c88d52f826..d4aca03199d 100644 --- a/mysql-test/suite/engines/funcs/t/up_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/up_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ UPDATE t1 SET c1 = NOW() WHERE c1 >= ADDTIME(NOW(),'2 02:01:01'); --sorted_result SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone;