From c6ad5c819ede1c0f3daf16b08281d92f93c312fc Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 10:51:31 +0100 Subject: [PATCH 01/21] Bug #59002 Please make mtr print correct file and line number when tests fail This patchs adds printing of a file stack (with line numbers) It does not fix the problem of a failure in the non-first iteration of a loop --- client/mysqltest.cc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index a12c56c9657..38f8516f7da 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1238,6 +1238,17 @@ static void cleanup_and_exit(int exit_code) exit(exit_code); } +void print_file_stack() +{ + for (struct st_test_file* err_file= cur_file; + err_file != file_stack; + err_file--) + { + fprintf(stderr, "included from %s at line %d:\n", + err_file->file_name, err_file->lineno); + } +} + void die(const char *fmt, ...) { static int dying= 0; @@ -1257,8 +1268,12 @@ void die(const char *fmt, ...) /* Print the error message */ fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) - fprintf(stderr, "In included file \"%s\": ", + { + fprintf(stderr, "In included file \"%s\": \n", cur_file->file_name); + print_file_stack(); + } + if (start_lineno > 0) fprintf(stderr, "At line %u: ", start_lineno); if (fmt) @@ -1288,20 +1303,14 @@ void die(const char *fmt, ...) void abort_not_supported_test(const char *fmt, ...) { va_list args; - struct st_test_file* err_file= cur_file; DBUG_ENTER("abort_not_supported_test"); /* Print include filestack */ fprintf(stderr, "The test '%s' is not supported by this installation\n", file_stack->file_name); fprintf(stderr, "Detected in file %s at line %d\n", - err_file->file_name, err_file->lineno); - while (err_file != file_stack) - { - err_file--; - fprintf(stderr, "included from %s at line %d\n", - err_file->file_name, err_file->lineno); - } + cur_file->file_name, cur_file->lineno); + print_file_stack(); /* Print error message */ va_start(args, fmt); From a18cde4734b8f94aa69741d614e8b4990c1befee Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 10:53:22 +0100 Subject: [PATCH 02/21] Bug #58896 MTR should recognise combinations as experimental without needing wildcards Added a pattern match to cover combinations Added to readme file --- mysql-test/collections/README.experimental | 6 +++++- mysql-test/collections/default.experimental | 2 +- mysql-test/lib/mtr_report.pm | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mysql-test/collections/README.experimental b/mysql-test/collections/README.experimental index 2f5ee7b00ab..924e062b76a 100644 --- a/mysql-test/collections/README.experimental +++ b/mysql-test/collections/README.experimental @@ -15,9 +15,13 @@ The syntax is as follows: and any subsequent characters are ignored. 4) The full test case name including the suite and execution mode - must be specified, for example: + may be specified, for example: main.alias 'row' # bug#00000 +4b) Now, combinations will also be covered if only the test name is + specified, for example: + rpl.rpl_ps # Covers 'row', 'mix' and 'stmt' + 5) As an exception to item 4, the last character of the test case specification may be an asterisk (*). In that case, all test cases that start with the same characters up to the last letter before the asterisk diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index aa2f2e9f724..1e6ff625d39 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -21,7 +21,7 @@ main.outfile_loaddata @solaris # joro : Bug #46895 ndb.* # joro : NDB tests marked as experimental as agreed with bochklin -rpl.rpl_innodb_bug28430* @solaris # Bug#46029 +rpl.rpl_innodb_bug28430 @solaris # Bug#46029 rpl.rpl_row_sp011 @solaris # Joro : Bug #54138 rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index 77f6920771d..42d93022392 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -129,7 +129,8 @@ sub mtr_report_test ($) { # Find out if this test case is an experimental one, so we can treat # the failure as an expected failure instead of a regression. for my $exp ( @$::experimental_test_cases ) { - if ( $exp ne $test_name ) { + # Include pattern match for combinations + if ( $exp ne $test_name && $test_name !~ /^$exp / ) { # if the expression is not the name of this test case, but has # an asterisk at the end, determine if the characters up to # but excluding the asterisk are the same From 063041853936b85446200e26a3da97a225e57aa0 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 10:54:42 +0100 Subject: [PATCH 03/21] Bug #58900 query_get_value crashes when result begins with dollar sign Generalized fix for recursive backtick Optional arg to eval_expr telling it not to interpret --- client/mysqltest.cc | 13 +++++++++---- mysql-test/r/mysqltest.result | 3 +++ mysql-test/t/mysqltest.test | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 38f8516f7da..feed964c2fa 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -474,7 +474,7 @@ VAR* var_init(VAR* v, const char *name, int name_len, const char *val, void var_free(void* v); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); -void eval_expr(VAR* v, const char *p, const char** p_end, bool backtick= true); +void eval_expr(VAR* v, const char *p, const char** p_end, bool do_eval= true); my_bool match_delimiter(int c, const char *delim, uint length); void dump_result_to_reject_file(char *buf, int size); void dump_warning_messages(); @@ -2371,7 +2371,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) break; } } - eval_expr(var, value, 0); + eval_expr(var, value, 0, false); } dynstr_free(&ds_query); mysql_free_result(res); @@ -2401,12 +2401,16 @@ void var_copy(VAR *dest, VAR *src) } -void eval_expr(VAR *v, const char *p, const char **p_end, bool backtick) +void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval) { DBUG_ENTER("eval_expr"); DBUG_PRINT("enter", ("p: '%s'", p)); + /* Skip to treat as pure string if no evaluation */ + if (! do_eval) + goto NO_EVAL; + if (*p == '$') { VAR *vp; @@ -2426,7 +2430,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool backtick) DBUG_VOID_RETURN; } - if (*p == '`' && backtick) + if (*p == '`') { var_query_set(v, p, p_end); DBUG_VOID_RETURN; @@ -2449,6 +2453,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool backtick) } } + NO_EVAL: { int new_val_len = (p_end && *p_end) ? (int) (*p_end - p) : (int) strlen(p); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 15730fff72c..00e4a598539 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -311,6 +311,9 @@ failing query in let create table t1 (a varchar(100)); insert into t1 values ('`select 42`'); `select 42` +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: Missing required argument 'filename' to command 'source' diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 56c86f7d431..52dfd8e86d3 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -859,6 +859,12 @@ insert into t1 values ('`select 42`'); let $a= `select * from t1`; # This should output `select 42`, not evaluate it again to 42 echo $a; +insert into t1 values ('$dollar'); +# These should also output the string without evaluating it. +let $a= query_get_value(select * from t1 order by a, a, 1); +echo $a; +let $a= query_get_value(select * from t1 order by a, a, 2); +echo $a; drop table t1; --error 1 From 5a66a6b86e22bb4a6bb16a5ab4c9c25193a0b420 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 14:27:03 +0100 Subject: [PATCH 04/21] Bug #58841 Generalise handling of plugins in MTR mysql-test-run.pl script Put descriptions of plugins into a separate file read by MTR MTR itself has generalised code to read this and set env. variables Removed the *SO variables, updated some tests accordingly New commit: added optional list of plugin names for _LOAD variable Also made changes for the new AUTH_* plugins --- mysql-test/include/plugin.defs | 41 +++++ mysql-test/mysql-test-run.pl | 201 +++++++---------------- mysql-test/suite/bugs/t/bug57108.test | 2 +- mysql-test/t/bug46261.test | 2 +- mysql-test/t/fulltext_plugin.test | 2 +- mysql-test/t/plugin.test | 10 +- mysql-test/t/plugin_auth_qa_2-master.opt | 4 +- mysql-test/t/plugin_auth_qa_3-master.opt | 4 +- mysql-test/t/plugin_not_embedded.test | 4 +- 9 files changed, 113 insertions(+), 157 deletions(-) create mode 100644 mysql-test/include/plugin.defs diff --git a/mysql-test/include/plugin.defs b/mysql-test/include/plugin.defs new file mode 100644 index 00000000000..4da03dc2cc9 --- /dev/null +++ b/mysql-test/include/plugin.defs @@ -0,0 +1,41 @@ +# Definition file for plugins. +# +# [,...] +# +# The following variables will be set for a plugin, where PLUGVAR +# represents the variable name given as the 3rd item +# +# PLUGVAR: name of plugin file including extension .so or .dll +# PLUGVAR_DIR: name of directory where plugin was found +# PLUGVAR_OPT: mysqld option --plugin_dir=.... +# PLUGVAR_LOAD: option --plugin_load=.... if the 4th element is present +# +# If a listed plugin is not found, the corresponding variables will be +# set to empty, they will not be unset. +# +# The PLUGVAR variable is not quoted, so you must remember to quote it +# when using it in an INSTALL PLUGIN command. +# +# The envorinment variables can be used in tests. If adding a new plugin, +# you are free to pick your variable name, but please keep it upper +# case for consistency. +# +# The _LOAD variable will have a form +# +# --plugin_load==;=..... +# +# with name1, name2 etc from the comma separated list of plugin names +# in the optional 4th argument. + +auth_test_plugin plugin/auth PLUGIN_AUTH test_plugin_server +qa_auth_interface plugin/auth PLUGIN_AUTH_INTERFACE qa_auth_interface +qa_auth_server plugin/auth PLUGIN_AUTH_SERVER qa_auth_server +qa_auth_client plugin/auth PLUGIN_AUTH_CLIENT qa_auth_client +udf_example sql UDF_EXAMPLE_LIB +ha_example storage/example EXAMPLE_PLUGIN EXAMPLE +semisync_master plugin/semisync SEMISYNC_MASTER_PLUGIN +semisync_slave plugin/semisync SEMISYNC_SLAVE_PLUGIN +ha_archive storage/archive ARCHIVE_PLUGIN +ha_blackhole storage/blackhole BLACKHOLE_PLUGIN +ha_federated storage/federated FEDERATED_PLUGIN +mypluglib plugin/fulltext SIMPLE_PARSER diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a7683b8d807..e2bb5d24205 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -131,10 +131,6 @@ my $opt_start_dirty; my $opt_start_exit; my $start_only; -my $auth_interface_fn; # the name of qa_auth_interface plugin -my $auth_server_fn; # the name of qa_auth_server plugin -my $auth_client_fn; # the name of qa_auth_client plugin -my $auth_filename; # the name of the authentication test plugin my $auth_plugin; # the path to the authentication test plugin END { @@ -1124,27 +1120,7 @@ sub command_line_setup { "$basedir/sql/share/charsets", "$basedir/share/charsets"); - # Look for auth test plugins - if (IS_WINDOWS) - { - $auth_filename = "auth_test_plugin.dll"; - $auth_interface_fn = "qa_auth_interface.dll"; - $auth_server_fn = "qa_auth_server.dll"; - $auth_client_fn = "qa_auth_client.dll"; - } - else - { - $auth_filename = "auth_test_plugin.so"; - $auth_interface_fn = "qa_auth_interface.so"; - $auth_server_fn = "qa_auth_server.so"; - $auth_client_fn = "qa_auth_client.so"; - } - $auth_plugin= - mtr_file_exists(vs_config_dirs('plugin/auth/',$auth_filename), - "$basedir/plugin/auth/.libs/" . $auth_filename, - "$basedir/lib/mysql/plugin/" . $auth_filename, - "$basedir/lib/plugin/" . $auth_filename); - + ($auth_plugin)= find_plugin("auth_test_plugin", "plugin/auth"); if (using_extern()) { @@ -1983,6 +1959,53 @@ sub find_plugin($$) return $lib_example_plugin; } +# +# Read plugin defintions file +# + +sub read_plugin_defs($) +{ + my ($defs_file)= @_; + + open(PLUGDEF, '<', $defs_file) + or mtr_error("Can't read plugin defintions file $defs_file"); + + while () { + next if /^#/; + my ($plug_file, $plug_loc, $plug_var, $plug_names)= split; + # Allow empty lines + next unless $plug_file; + mtr_error("Lines in $defs_file must have 3 or 4 items") unless $plug_var; + + my ($plugin)= find_plugin($plug_file, $plug_loc); + + # Set env. variables that tests may use, set to empty if plugin + # listed in def. file but not found. + + if ($plugin) { + $ENV{$plug_var}= basename($plugin); + $ENV{$plug_var.'_DIR'}= dirname($plugin); + $ENV{$plug_var.'_OPT'}= "--plugin-dir=".dirname($plugin); + if ($plug_names) { + my $lib_name= basename($plugin); + my $load_var= "--plugin_load="; + my $semi= ''; + foreach my $plug_name (split (',', $plug_names)) { + $load_var .= $semi . "$plug_name=$lib_name"; + $semi= ';'; + } + $ENV{$plug_var.'_LOAD'}= $load_var; + } + } else { + $ENV{$plug_var}= ""; + $ENV{$plug_var.'_DIR'}= ""; + $ENV{$plug_var.'_OPT'}= ""; + $ENV{$plug_var.'_LOAD'}= "" if $plug_names; + } + } + close PLUGDEF; +} + sub environment_setup { umask(022); @@ -2019,127 +2042,19 @@ sub environment_setup { } # -------------------------------------------------------------------------- - # Add the path where mysqld will find udf_example.so + # Read definitions from include/plugin.defs + # + # Plugin settings should no longer be added here, instead + # place definitions in include/plugin.defs. + # See comment in that file for details. # -------------------------------------------------------------------------- - my $udf_example_filename; - if (IS_WINDOWS) + read_plugin_defs("include/plugin.defs"); + + # Simplify reference to semisync plugins + if ($ENV{'SEMISYNC_MASTER_PLUGIN'}) { - $udf_example_filename = "udf_example.dll"; + $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'}; } - else - { - $udf_example_filename = "udf_example.so"; - } - my $lib_udf_example= - mtr_file_exists(vs_config_dirs('sql', $udf_example_filename), - "$basedir/sql/.libs/$udf_example_filename",); - - if ( $lib_udf_example ) - { - push(@ld_library_paths, dirname($lib_udf_example)); - } - - $ENV{'UDF_EXAMPLE_LIB'}= - ($lib_udf_example ? basename($lib_udf_example) : ""); - $ENV{'UDF_EXAMPLE_LIB_OPT'}= "--plugin-dir=". - ($lib_udf_example ? dirname($lib_udf_example) : ""); - - # -------------------------------------------------------------------------- - # Add the path where mysqld will find the auth test plugin (dialog.so/dll) - # -------------------------------------------------------------------------- - if ($auth_plugin) - { - $ENV{'PLUGIN_AUTH'}= basename($auth_plugin); - $ENV{'PLUGIN_AUTH_OPT'}= "--plugin-dir=".dirname($auth_plugin); - - $ENV{'PLUGIN_AUTH_LOAD'}="--plugin_load=test_plugin_server=".$auth_filename; - $ENV{'PLUGIN_AUTH_INTERFACE'}="--plugin_load=qa_auth_interface=".$auth_interface_fn; - $ENV{'PLUGIN_AUTH_SERVER'}="--plugin_load=qa_auth_server=".$auth_server_fn; - $ENV{'PLUGIN_AUTH_CLIENT'}="--plugin_load=qa_auth_client=".$auth_client_fn; - } - else - { - $ENV{'PLUGIN_AUTH'}= ""; - $ENV{'PLUGIN_AUTH_OPT'}="--plugin-dir="; - $ENV{'PLUGIN_AUTH_LOAD'}=""; - $ENV{'PLUGIN_AUTH_INTERFACE'}=""; - $ENV{'PLUGIN_AUTH_SERVER'}=""; - $ENV{'PLUGIN_AUTH_CLIENT'}=""; - } - - - # -------------------------------------------------------------------------- - # Add the path where mysqld will find ha_example.so - # -------------------------------------------------------------------------- - if ($mysql_version_id >= 50100) { - my ($lib_example_plugin) = find_plugin("ha_example", "storage/example"); - - if($lib_example_plugin) - { - $ENV{'EXAMPLE_PLUGIN'}= - ($lib_example_plugin ? basename($lib_example_plugin) : ""); - $ENV{'EXAMPLE_PLUGIN_OPT'}= "--plugin-dir=". - ($lib_example_plugin ? dirname($lib_example_plugin) : ""); - - $ENV{'HA_EXAMPLE_SO'}="'".basename($lib_example_plugin)."'"; - $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".basename($lib_example_plugin); - } - else - { - # Some ".opt" files use some of these variables, so they must be defined - $ENV{'EXAMPLE_PLUGIN'}= ""; - $ENV{'EXAMPLE_PLUGIN_OPT'}= ""; - $ENV{'HA_EXAMPLE_SO'}= ""; - $ENV{'EXAMPLE_PLUGIN_LOAD'}= ""; - } - } - - - # -------------------------------------------------------------------------- - # Add the path where mysqld will find semisync plugins - # -------------------------------------------------------------------------- - if (!$opt_embedded_server) { - - - my ($lib_semisync_master_plugin) = find_plugin("semisync_master", "plugin/semisync"); - my ($lib_semisync_slave_plugin) = find_plugin("semisync_slave", "plugin/semisync"); - - - if ($lib_semisync_master_plugin && $lib_semisync_slave_plugin) - { - $ENV{'SEMISYNC_MASTER_PLUGIN'}= basename($lib_semisync_master_plugin); - $ENV{'SEMISYNC_SLAVE_PLUGIN'}= basename($lib_semisync_slave_plugin); - $ENV{'SEMISYNC_PLUGIN_OPT'}= "--plugin-dir=".dirname($lib_semisync_master_plugin); - } - else - { - $ENV{'SEMISYNC_MASTER_PLUGIN'}= ""; - $ENV{'SEMISYNC_SLAVE_PLUGIN'}= ""; - $ENV{'SEMISYNC_PLUGIN_OPT'}="--plugin-dir="; - } - } - - # ---------------------------------------------------- - # Add the paths where mysqld will find archive/blackhole/federated plugins. - # ---------------------------------------------------- - $ENV{'ARCHIVE_PLUGIN_DIR'} = - dirname(find_plugin("ha_archive", "storage/archive")); - $ENV{'BLACKHOLE_PLUGIN_DIR'} = - dirname(find_plugin("ha_blackhole", "storage/blackhole")); - $ENV{'FEDERATED_PLUGIN_DIR'} = - dirname(find_plugin("ha_federated", "storage/federated")); - - # ---------------------------------------------------- - # Add the path where mysqld will find mypluglib.so - # ---------------------------------------------------- - - my ($lib_simple_parser) = find_plugin("mypluglib", "plugin/fulltext"); - - $ENV{'MYPLUGLIB_SO'}="'".basename($lib_simple_parser)."'"; - $ENV{'SIMPLE_PARSER'}= - ($lib_simple_parser ? basename($lib_simple_parser) : ""); - $ENV{'SIMPLE_PARSER_OPT'}= "--plugin-dir=". - ($lib_simple_parser ? dirname($lib_simple_parser) : ""); # -------------------------------------------------------------------------- # Valgrind need to be run with debug libraries otherwise it's almost diff --git a/mysql-test/suite/bugs/t/bug57108.test b/mysql-test/suite/bugs/t/bug57108.test index 1006a7b30f1..56acd7fe7bd 100644 --- a/mysql-test/suite/bugs/t/bug57108.test +++ b/mysql-test/suite/bugs/t/bug57108.test @@ -5,7 +5,7 @@ # switched directory after starting the server and am using a relative # --defaults-file. --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; --query_vertical SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile diff --git a/mysql-test/t/bug46261.test b/mysql-test/t/bug46261.test index 67bdc995850..e0eae9b86fb 100644 --- a/mysql-test/t/bug46261.test +++ b/mysql-test/t/bug46261.test @@ -7,7 +7,7 @@ --replace_regex /\.dll/.so/ --error ER_OPTION_PREVENTS_STATEMENT -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; --replace_regex /\.dll/.so/ --error ER_OPTION_PREVENTS_STATEMENT diff --git a/mysql-test/t/fulltext_plugin.test b/mysql-test/t/fulltext_plugin.test index 25e4302ef0d..b591a7949e5 100644 --- a/mysql-test/t/fulltext_plugin.test +++ b/mysql-test/t/fulltext_plugin.test @@ -4,7 +4,7 @@ # BUG#39746 - Debug flag breaks struct definition (server crash) # --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN simple_parser SONAME $MYPLUGLIB_SO; +eval INSTALL PLUGIN simple_parser SONAME '$SIMPLE_PARSER'; CREATE TABLE t1(a TEXT, b TEXT, FULLTEXT(a) WITH PARSER simple_parser); ALTER TABLE t1 ADD FULLTEXT(b) WITH PARSER simple_parser; DROP TABLE t1; diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test index 0bf86b47dd7..117eaf1e19b 100644 --- a/mysql-test/t/plugin.test +++ b/mysql-test/t/plugin.test @@ -5,15 +5,15 @@ CREATE TABLE t1(a int) ENGINE=EXAMPLE; DROP TABLE t1; --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; --replace_regex /\.dll/.so/ --error 1125 -eval INSTALL PLUGIN EXAMPLE SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN EXAMPLE SONAME '$EXAMPLE_PLUGIN'; UNINSTALL PLUGIN example; --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; CREATE TABLE t1(a int) ENGINE=EXAMPLE; @@ -41,7 +41,7 @@ UNINSTALL PLUGIN non_exist; --echo # to impossible int val --echo # --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; SET GLOBAL example_enum_var= e1; SET GLOBAL example_enum_var= e2; @@ -56,7 +56,7 @@ UNINSTALL PLUGIN example; # Bug #32757 hang with sql_mode set when setting some global variables # --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; select @@session.sql_mode into @old_sql_mode; diff --git a/mysql-test/t/plugin_auth_qa_2-master.opt b/mysql-test/t/plugin_auth_qa_2-master.opt index c29153ac95b..354907b9366 100644 --- a/mysql-test/t/plugin_auth_qa_2-master.opt +++ b/mysql-test/t/plugin_auth_qa_2-master.opt @@ -1,2 +1,2 @@ -$PLUGIN_AUTH_OPT -$PLUGIN_AUTH_INTERFACE +$PLUGIN_AUTH_INTERFACE_OPT +$PLUGIN_AUTH_INTERFACE_LOAD diff --git a/mysql-test/t/plugin_auth_qa_3-master.opt b/mysql-test/t/plugin_auth_qa_3-master.opt index 5cc2af0a358..e1754862a4d 100644 --- a/mysql-test/t/plugin_auth_qa_3-master.opt +++ b/mysql-test/t/plugin_auth_qa_3-master.opt @@ -1,2 +1,2 @@ -$PLUGIN_AUTH_OPT -$PLUGIN_AUTH_SERVER +$PLUGIN_AUTH_SERVER_OPT +$PLUGIN_AUTH_SERVER_LOAD diff --git a/mysql-test/t/plugin_not_embedded.test b/mysql-test/t/plugin_not_embedded.test index 40024efcaad..a2b7b8a0fe4 100644 --- a/mysql-test/t/plugin_not_embedded.test +++ b/mysql-test/t/plugin_not_embedded.test @@ -8,7 +8,7 @@ GRANT INSERT ON mysql.plugin TO bug51770@localhost; connect(con1,localhost,bug51770,,); --replace_regex /\.dll/.so/ -eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; --error ER_TABLEACCESS_DENIED_ERROR UNINSTALL PLUGIN example; connection default; @@ -25,7 +25,7 @@ DROP USER bug51770@localhost; # The bug consisted of not recognizing / on Windows, so checking / on # all platforms should cover this case. -let $path = `select CONCAT_WS('/', '..', $HA_EXAMPLE_SO)`; +let $path = `select CONCAT_WS('/', '..', '$EXAMPLE_PLUGIN')`; --replace_regex /\.dll/.so/ --error ER_UDF_NO_PATHS eval INSTALL PLUGIN example SONAME '$path'; From 596c881092f7a973f13ab8d110ab538da4cda8eb Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 15:00:21 +0100 Subject: [PATCH 05/21] Bug #59002 Please make mtr print correct file and line number when tests fail Followup: had forgotten to update mysqltest.test due to changed output - duh! --- mysql-test/r/mysqltest.result | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 00e4a598539..a16b3ec2670 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -318,8 +318,26 @@ 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: 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": At line 1: Source directives are nesting too deep -mysqltest: In included file "MYSQLTEST_VARDIR/tmp/error.sql": At line 1: query 'garbage ' 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 'garbage' at line 1 +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +included from MYSQLTEST_VARDIR/tmp/recursive.sql at line 1: +At line 1: Source directives are nesting too deep +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/error.sql": +included from MYSQLTEST_VARDIR/tmp/error.sql at line 1: +At line 1: query 'garbage ' 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 'garbage' at line 1 2 = outer loop variable after while here is the sourced script @@ -413,7 +431,9 @@ Beta is true while with string, only once 1 Testing while with not -mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest_while.inc": At line 64: Nesting too deeply +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest_while.inc": +included from MYSQLTEST_VARDIR/tmp/mysqltest_while.inc at line 65: +At line 64: Nesting too deeply mysqltest: At line 1: missing '(' in while mysqltest: At line 1: missing ')' in while mysqltest: At line 1: Missing '{' after while. Found "dec $i" @@ -462,8 +482,12 @@ mysqltest: At line 1: query 'connect con2,localhost,root,,illegal_db' failed: 1 mysqltest: At line 1: Illegal argument for port: 'illegal_port' mysqltest: At line 1: Illegal option to connect: SMTP 200 connects succeeded -mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 3: connection 'test_con1' not found in connection pool -mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 2: Connection test_con1 already exists +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": +included from MYSQLTEST_VARDIR/tmp/mysqltest.sql at line 3: +At line 3: connection 'test_con1' not found in connection pool +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": +included from MYSQLTEST_VARDIR/tmp/mysqltest.sql at line 2: +At line 2: Connection test_con1 already exists show tables; ERROR 3D000: No database selected connect con1,localhost,root,,; From 3261c83722b228c164a744a88df20c1c93d4b766 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 15:16:29 +0100 Subject: [PATCH 06/21] Bug #59216 mysql test suite can not run indiviual tests in engines/funcs suite Test name spec would be cut at last / Only do this when .test file name given, not suite. --- 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 f1f1ac35dcd..856982e98a1 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -229,8 +229,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 443b3bed2f077b86d6e4d5e4f87c96b0c571d595 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 11 Jan 2011 15:23:39 +0100 Subject: [PATCH 07/21] Bug #59153 mysqltest produces a valgrind warning when the running test fails Local variable ds_warnings in run_query not cleared. But when we call die() we don't have access to it. Set global var. to point to it when allocated. --- client/mysqltest.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 63e74cf0b32..6d1630ebdaa 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -468,6 +468,8 @@ TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; DYNAMIC_STRING ds_res; +/* Points to ds_warning in run_query, so it can be freed */ +DYNAMIC_STRING *ds_warn= 0; char builtin_echo[FN_REFLEN]; @@ -1275,6 +1277,8 @@ void free_used_memory() my_free(embedded_server_args[--embedded_server_arg_count]); delete_dynamic(&q_lines); dynstr_free(&ds_res); + if (ds_warn) + dynstr_free(ds_warn); free_all_replace(); my_free(opt_pass); free_defaults(default_argv); @@ -7693,6 +7697,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) die ("Cannot reap on a connection without pending send"); init_dynamic_string(&ds_warnings, NULL, 0, 256); + ds_warn= &ds_warnings; + /* Evaluate query if this is an eval command */ @@ -7850,6 +7856,7 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) ds, &ds_warnings); dynstr_free(&ds_warnings); + ds_warn= 0; if (command->type == Q_EVAL || command->type == Q_SEND_EVAL) dynstr_free(&eval_query); From a27de1946855143ec40374d57d6a1999841cb4a4 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 12 Jan 2011 10:27:46 +0100 Subject: [PATCH 08/21] Bug #59182 output of mysql-test-run.pl - mismatch between col names and actual col contents New patch, avoid global $opt_parallel I still prefer not to print workerid when not doing parallel --- mysql-test/lib/mtr_report.pm | 15 ++++++++++----- mysql-test/mysql-test-run.pl | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index 3be679858bc..cd3f9ce1041 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -396,7 +396,7 @@ sub mtr_report_stats ($$;$) { ############################################################################## sub mtr_print_line () { - print '-' x 60 . "\n"; + print '-' x 74 . "\n"; } @@ -406,13 +406,18 @@ sub mtr_print_thick_line { } -sub mtr_print_header () { +sub mtr_print_header ($) { + my ($wid) = @_; print "\n"; printf "TEST"; - print " " x 38; + if ($wid) { + print " " x 34 . "WORKER "; + } else { + print " " x 38; + } print "RESULT "; - print "TIME (ms)" if $timer; - print "\n"; + print "TIME (ms) or " if $timer; + print "COMMENT\n"; mtr_print_line(); print "\n"; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e2bb5d24205..83f6a83682d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -438,7 +438,7 @@ sub main { mtr_report(); mtr_print_thick_line(); - mtr_print_header(); + mtr_print_header($opt_parallel > 1); mark_time_used('init'); From d6922c7e836a7f546c477828fab02d6b921fd551 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Wed, 12 Jan 2011 15:58:47 +0300 Subject: [PATCH 09/21] Bug#59330: Incorrect result when comparing an aggregate function with TIMESTAMP. Item_cache::get_cache wasn't treating TIMESTAMP as a DATETIME value thus returning string cache for items with TIMESTAMP type. This led to incorrect TIMESTAMP -> INT conversion and to a wrong query result. Fixed by using Item::is_datetime function to check for DATETIME type group. --- mysql-test/r/type_timestamp.result | 29 +++++++++++++++++++++++++++++ mysql-test/t/type_timestamp.test | 18 ++++++++++++++++++ sql/item.cc | 3 +-- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 10a2b47ba02..d5769bfd59a 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -540,3 +540,32 @@ a 2010-03-05 11:08:02 DROP TABLE t1; End of Bug#50888 +# +# Bug59330: Incorrect result when comparing an aggregate +# function with TIMESTAMP +# +CREATE TABLE t1 (dt DATETIME, ts TIMESTAMP); +INSERT INTO t1 VALUES('2011-01-06 12:34:30', '2011-01-06 12:34:30'); +SELECT MAX(dt), MAX(ts) FROM t1; +MAX(dt) MAX(ts) +2011-01-06 12:34:30 2011-01-06 12:34:30 +SELECT MAX(ts) < '2010-01-01 00:00:00' FROM t1; +MAX(ts) < '2010-01-01 00:00:00' +0 +SELECT MAX(dt) < '2010-01-01 00:00:00' FROM t1; +MAX(dt) < '2010-01-01 00:00:00' +0 +SELECT MAX(ts) > '2010-01-01 00:00:00' FROM t1; +MAX(ts) > '2010-01-01 00:00:00' +1 +SELECT MAX(dt) > '2010-01-01 00:00:00' FROM t1; +MAX(dt) > '2010-01-01 00:00:00' +1 +SELECT MAX(ts) = '2011-01-06 12:34:30' FROM t1; +MAX(ts) = '2011-01-06 12:34:30' +1 +SELECT MAX(dt) = '2011-01-06 12:34:30' FROM t1; +MAX(dt) = '2011-01-06 12:34:30' +1 +DROP TABLE t1; +End of 5.5 tests diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index dfac6f93b7d..76423b11b99 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -377,3 +377,21 @@ SELECT a FROM t1; DROP TABLE t1; --echo End of Bug#50888 + +--echo # +--echo # Bug59330: Incorrect result when comparing an aggregate +--echo # function with TIMESTAMP +--echo # +CREATE TABLE t1 (dt DATETIME, ts TIMESTAMP); +INSERT INTO t1 VALUES('2011-01-06 12:34:30', '2011-01-06 12:34:30'); +SELECT MAX(dt), MAX(ts) FROM t1; +SELECT MAX(ts) < '2010-01-01 00:00:00' FROM t1; +SELECT MAX(dt) < '2010-01-01 00:00:00' FROM t1; +SELECT MAX(ts) > '2010-01-01 00:00:00' FROM t1; +SELECT MAX(dt) > '2010-01-01 00:00:00' FROM t1; +SELECT MAX(ts) = '2011-01-06 12:34:30' FROM t1; +SELECT MAX(dt) = '2011-01-06 12:34:30' FROM t1; +DROP TABLE t1; + +--echo End of 5.5 tests + diff --git a/sql/item.cc b/sql/item.cc index 18a88d64470..c7787d65c22 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7370,8 +7370,7 @@ Item_cache* Item_cache::get_cache(const Item *item, const Item_result type) return new Item_cache_decimal(); case STRING_RESULT: /* Not all functions that return DATE/TIME are actually DATE/TIME funcs. */ - if ((item->field_type() == MYSQL_TYPE_DATE || - item->field_type() == MYSQL_TYPE_DATETIME || + if ((item->is_datetime() || item->field_type() == MYSQL_TYPE_TIME) && (const_cast(item))->result_as_longlong()) return new Item_cache_datetime(item->field_type()); From e073e2c0be3860eafd08b2ab14c8490dcb3b05fc Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Wed, 12 Jan 2011 17:02:41 +0400 Subject: [PATCH 10/21] Bug #57321 crashes and valgrind errors from spatial types Item_func_spatial_collection::fix_length_and_dec didn't call parent's method, so the maybe_null was set to '0' after it. But in this case the result was just NULL, that caused wrong behaviour. per-file comments: mysql-test/r/gis.result Bug #57321 crashes and valgrind errors from spatial types test result updated. mysql-test/t/gis.test Bug #57321 crashes and valgrind errors from spatial types test case added. sql/item_geofunc.h Bug #57321 crashes and valgrind errors from spatial types Item_func_geometry::fix_length_and_dec() called in Item_func_spatial_collection::fix_length_and_dec(). --- mysql-test/r/gis.result | 8 ++++++++ mysql-test/t/gis.test | 10 ++++++++++ sql/item_geofunc.h | 1 + 3 files changed, 19 insertions(+) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 3b18ee61336..f4aa361ffcf 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1014,4 +1014,12 @@ SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000 SET @a=POLYFROMWKB(@a); SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; SET @a=POLYFROMWKB(@a); +create table t1(a polygon NOT NULL)engine=myisam; +insert into t1 values (geomfromtext("point(0 1)")); +insert into t1 values (geomfromtext("point(1 0)")); +select * from (select polygon(t1.a) as p from t1 order by t1.a) d; +p +NULL +NULL +drop table t1; End of 5.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index fd0a18ab4dd..97fc6f94b6a 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -744,4 +744,14 @@ SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000 SET @a=POLYFROMWKB(@a); +# +# Bug #57321 crashes and valgrind errors from spatial types +# + +create table t1(a polygon NOT NULL)engine=myisam; +insert into t1 values (geomfromtext("point(0 1)")); +insert into t1 values (geomfromtext("point(1 0)")); +select * from (select polygon(t1.a) as p from t1 order by t1.a) d; +drop table t1; + --echo End of 5.1 tests diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index b3ecbc39933..08161badfd3 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -177,6 +177,7 @@ public: String *val_str(String *); void fix_length_and_dec() { + Item_geometry_func::fix_length_and_dec(); for (unsigned int i= 0; i < arg_count; ++i) { if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) From 94fbedd3e3f17a624c5e66f3914b67d9f46d1b2b Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Wed, 12 Jan 2011 16:08:30 +0300 Subject: [PATCH 11/21] Fix for bug #58499 "DEFINER-security view selecting from INVOKER-security view access check wrong". When privilege checks were done for tables used from an INVOKER-security view which in its turn was used from a DEFINER-security view connection's active security context was incorrectly used instead of security context with privileges of the second view's creator. This meant that users which had enough rights to access the DEFINER-security view and as result were supposed to be able successfully access it were unable to do so in cases when they didn't have privileges on underlying tables of the INVOKER-security view. This problem was caused by the fact that for INVOKER-security views TABLE_LIST::security_ctx member for underlying tables were set to 0 even in cases when particular view was used from another DEFINER-security view. This meant that when checks of privileges on these underlying tables was done in setup_tables_and_check_access() active connection security context was used instead of context corresponding to the creator of caller view. This fix addresses the problem by ensuring that underlying tables of an INVOKER-security view inherit security context from the view and thus correct security context is used for privilege checks on underlying tables in cases when such view is used from another view with DEFINER-security. --- mysql-test/r/view_grant.result | 126 +++++++++++++++++++++++++++++ mysql-test/t/view_grant.test | 144 ++++++++++++++++++++++++++++++++- sql/sql_view.cc | 42 ++++++---- 3 files changed, 296 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 52c8bc8a3d5..0348a8428a5 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -1248,3 +1248,129 @@ Note 1449 The user specified as a definer ('unknown'@'unknown') does not exist LOCK TABLES v1 READ; ERROR HY000: The user specified as a definer ('unknown'@'unknown') does not exist DROP VIEW v1; +# +# Bug #58499 "DEFINER-security view selecting from INVOKER-security view +# access check wrong". +# +# Check that we correctly handle privileges for various combinations +# of INVOKER and DEFINER-security views using each other. +DROP DATABASE IF EXISTS mysqltest1; +CREATE DATABASE mysqltest1; +USE mysqltest1; +CREATE TABLE t1 (i INT); +CREATE TABLE t2 (j INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +# +# 1) DEFINER-security view uses INVOKER-security view (covers +# scenario originally described in the bug report). +CREATE SQL SECURITY INVOKER VIEW v1_uses_t1 AS SELECT * FROM t1; +CREATE SQL SECURITY INVOKER VIEW v1_uses_t2 AS SELECT * FROM t2; +CREATE USER 'mysqluser1'@'%'; +GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser1'@'%'; +GRANT SELECT ON t1 TO 'mysqluser1'@'%'; +# To be able create 'v2_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t1 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t2 TO 'mysqluser1'@'%'; +# +# Connection 'mysqluser1'. +CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +# +# Connection 'default'. +CREATE USER 'mysqluser2'@'%'; +GRANT SELECT ON v2_uses_t1 TO 'mysqluser2'@'%'; +GRANT SELECT ON v2_uses_t2 TO 'mysqluser2'@'%'; +GRANT SELECT ON t2 TO 'mysqluser2'@'%'; +GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser2'@'%'; +# Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +# +# Connection 'mysqluser2'. +# The below statement should succeed thanks to suid nature of v2_uses_t1. +SELECT * FROM v2_uses_t1; +i +1 +# The below statement should fail due to suid nature of v2_uses_t2. +SELECT * FROM v2_uses_t2; +ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +# +# 2) INVOKER-security view uses INVOKER-security view. +# +# Connection 'default'. +DROP VIEW v2_uses_t1, v2_uses_t2; +CREATE SQL SECURITY INVOKER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY INVOKER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +GRANT SELECT ON v2_uses_t1 TO 'mysqluser1'@'%'; +GRANT SELECT ON v2_uses_t2 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t1 TO 'mysqluser2'@'%'; +GRANT SELECT ON v1_uses_t2 TO 'mysqluser2'@'%'; +# +# Connection 'mysqluser1'. +# For both versions of 'v2' 'mysqluser1' privileges should be used. +SELECT * FROM v2_uses_t1; +i +1 +SELECT * FROM v2_uses_t2; +ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +# +# Connection 'mysqluser2'. +# And now for both versions of 'v2' 'mysqluser2' privileges should +# be used. +SELECT * FROM v2_uses_t1; +ERROR HY000: View 'mysqltest1.v2_uses_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT * FROM v2_uses_t2; +j +2 +# +# 3) INVOKER-security view uses DEFINER-security view. +# +# Connection 'default'. +DROP VIEW v1_uses_t1, v1_uses_t2; +# To be able create 'v1_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +# +# Connection 'mysqluser1'. +CREATE SQL SECURITY DEFINER VIEW v1_uses_t1 AS SELECT * FROM t1; +CREATE SQL SECURITY DEFINER VIEW v1_uses_t2 AS SELECT * FROM t2; +# +# Connection 'default'. +# Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +# +# Connection 'mysqluser2'. +# Due to suid nature of v1_uses_t1 and v1_uses_t2 the first +# select should succeed and the second select should fail. +SELECT * FROM v2_uses_t1; +i +1 +SELECT * FROM v2_uses_t2; +ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +# +# 4) DEFINER-security view uses DEFINER-security view. +# +# Connection 'default'. +DROP VIEW v2_uses_t1, v2_uses_t2; +# To be able create 'v2_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +# +# Connection 'mysqluser2'. +CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +# +# Connection 'default'. +# Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +# +# Connection 'mysqluser2'. +# Again privileges of creator of innermost views should apply. +SELECT * FROM v2_uses_t1; +i +1 +SELECT * FROM v2_uses_t2; +ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +USE test; +DROP DATABASE mysqltest1; +DROP USER 'mysqluser1'@'%'; +DROP USER 'mysqluser2'@'%'; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index ba603bde7f8..21c6f376f8a 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1503,8 +1503,6 @@ SHOW CREATE VIEW v1; DROP TABLE t1; DROP VIEW v1; -# Wait till we reached the initial number of concurrent sessions ---source include/wait_until_count_sessions.inc --echo # --echo # Bug #46019: ERROR 1356 When selecting from within another @@ -1546,3 +1544,145 @@ CREATE DEFINER=`unknown`@`unknown` SQL SECURITY DEFINER VIEW v1 AS SELECT 1; --error ER_NO_SUCH_USER LOCK TABLES v1 READ; DROP VIEW v1; + + +--echo # +--echo # Bug #58499 "DEFINER-security view selecting from INVOKER-security view +--echo # access check wrong". +--echo # +--echo # Check that we correctly handle privileges for various combinations +--echo # of INVOKER and DEFINER-security views using each other. +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +--enable_warnings +CREATE DATABASE mysqltest1; +USE mysqltest1; +CREATE TABLE t1 (i INT); +CREATE TABLE t2 (j INT); +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2); +--echo # +--echo # 1) DEFINER-security view uses INVOKER-security view (covers +--echo # scenario originally described in the bug report). +CREATE SQL SECURITY INVOKER VIEW v1_uses_t1 AS SELECT * FROM t1; +CREATE SQL SECURITY INVOKER VIEW v1_uses_t2 AS SELECT * FROM t2; +CREATE USER 'mysqluser1'@'%'; +GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser1'@'%'; +GRANT SELECT ON t1 TO 'mysqluser1'@'%'; +--echo # To be able create 'v2_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t1 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t2 TO 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser1'. +--connect (mysqluser1, localhost, mysqluser1,,mysqltest1) +CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +--echo # +--echo # Connection 'default'. +--connection default +CREATE USER 'mysqluser2'@'%'; +GRANT SELECT ON v2_uses_t1 TO 'mysqluser2'@'%'; +GRANT SELECT ON v2_uses_t2 TO 'mysqluser2'@'%'; +GRANT SELECT ON t2 TO 'mysqluser2'@'%'; +GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser2'@'%'; +--echo # Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser2'. +--connect (mysqluser2, localhost, mysqluser2,,mysqltest1) +--echo # The below statement should succeed thanks to suid nature of v2_uses_t1. +SELECT * FROM v2_uses_t1; +--echo # The below statement should fail due to suid nature of v2_uses_t2. +--error ER_VIEW_INVALID +SELECT * FROM v2_uses_t2; +--echo # +--echo # 2) INVOKER-security view uses INVOKER-security view. +--echo # +--echo # Connection 'default'. +--connection default +DROP VIEW v2_uses_t1, v2_uses_t2; +CREATE SQL SECURITY INVOKER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY INVOKER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +GRANT SELECT ON v2_uses_t1 TO 'mysqluser1'@'%'; +GRANT SELECT ON v2_uses_t2 TO 'mysqluser1'@'%'; +GRANT SELECT ON v1_uses_t1 TO 'mysqluser2'@'%'; +GRANT SELECT ON v1_uses_t2 TO 'mysqluser2'@'%'; +--echo # +--echo # Connection 'mysqluser1'. +--connection mysqluser1 +--echo # For both versions of 'v2' 'mysqluser1' privileges should be used. +SELECT * FROM v2_uses_t1; +--error ER_VIEW_INVALID +SELECT * FROM v2_uses_t2; +--echo # +--echo # Connection 'mysqluser2'. +--connection mysqluser2 +--echo # And now for both versions of 'v2' 'mysqluser2' privileges should +--echo # be used. +--error ER_VIEW_INVALID +SELECT * FROM v2_uses_t1; +SELECT * FROM v2_uses_t2; +--echo # +--echo # 3) INVOKER-security view uses DEFINER-security view. +--echo # +--echo # Connection 'default'. +--connection default +DROP VIEW v1_uses_t1, v1_uses_t2; +--echo # To be able create 'v1_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser1'. +--connection mysqluser1 +CREATE SQL SECURITY DEFINER VIEW v1_uses_t1 AS SELECT * FROM t1; +CREATE SQL SECURITY DEFINER VIEW v1_uses_t2 AS SELECT * FROM t2; +--echo # +--echo # Connection 'default'. +--connection default +--echo # Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser2'. +--connection mysqluser2 +--echo # Due to suid nature of v1_uses_t1 and v1_uses_t2 the first +--echo # select should succeed and the second select should fail. +SELECT * FROM v2_uses_t1; +--error ER_VIEW_INVALID +SELECT * FROM v2_uses_t2; +--echo # +--echo # 4) DEFINER-security view uses DEFINER-security view. +--echo # +--echo # Connection 'default'. +--connection default +DROP VIEW v2_uses_t1, v2_uses_t2; +--echo # To be able create 'v2_uses_t2' we also need select on t2. +GRANT SELECT ON t2 TO 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser2'. +--connection mysqluser2 +CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1; +CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2; +--echo # +--echo # Connection 'default'. +--connection default +--echo # Make 'mysqluser1' unable to access t2. +REVOKE SELECT ON t2 FROM 'mysqluser1'@'%'; +--echo # +--echo # Connection 'mysqluser2'. +--connection mysqluser2 +--echo # Again privileges of creator of innermost views should apply. +SELECT * FROM v2_uses_t1; +--error ER_VIEW_INVALID +SELECT * FROM v2_uses_t2; + +--disconnect mysqluser1 +--disconnect mysqluser2 +--connection default +USE test; +DROP DATABASE mysqltest1; +DROP USER 'mysqluser1'@'%'; +DROP USER 'mysqluser2'@'%'; + + +# Wait till we reached the initial number of concurrent sessions +--source include/wait_until_count_sessions.inc diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 6cb4f590ae0..a25ef931344 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1255,6 +1255,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; + Security_context *security_ctx; /* Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show @@ -1396,25 +1397,38 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, if (table->view_suid) { /* - Prepare a security context to check underlying objects of the view + For suid views prepare a security context for checking underlying + objects of the view. */ if (!(table->view_sctx= (Security_context *) thd->stmt_arena->alloc(sizeof(Security_context)))) goto err; - /* Assign the context to the tables referenced in the view */ - if (view_tables) - { - DBUG_ASSERT(view_tables_tail); - for (tbl= view_tables; tbl != view_tables_tail->next_global; - tbl= tbl->next_global) - tbl->security_ctx= table->view_sctx; - } - /* assign security context to SELECT name resolution contexts of view */ - for(SELECT_LEX *sl= lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) - sl->context.security_ctx= table->view_sctx; + security_ctx= table->view_sctx; } + else + { + /* + For non-suid views inherit security context from view's table list. + This allows properly handle situation when non-suid view is used + from within suid view. + */ + security_ctx= table->security_ctx; + } + + /* Assign the context to the tables referenced in the view */ + if (view_tables) + { + DBUG_ASSERT(view_tables_tail); + for (tbl= view_tables; tbl != view_tables_tail->next_global; + tbl= tbl->next_global) + tbl->security_ctx= security_ctx; + } + + /* assign security context to SELECT name resolution contexts of view */ + for(SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + sl->context.security_ctx= security_ctx; /* Setup an error processor to hide error messages issued by stored From add4385d8d4014992ce35695b40004a88c507109 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 12 Jan 2011 14:17:54 +0100 Subject: [PATCH 12/21] Bug #58841 Generalise handling of plugins in MTR mysql-test-run.pl script Follow-up fix: mtr died if trying to run semisync test w/o the plugin --- mysql-test/mysql-test-run.pl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 83f6a83682d..b786066faf6 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2051,10 +2051,7 @@ sub environment_setup { read_plugin_defs("include/plugin.defs"); # Simplify reference to semisync plugins - if ($ENV{'SEMISYNC_MASTER_PLUGIN'}) - { - $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'}; - } + $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'}; # -------------------------------------------------------------------------- # Valgrind need to be run with debug libraries otherwise it's almost From 51c6f8ebac9eb94b87cc56da9e913dc9878f3a1e Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 12 Jan 2011 19:32:45 +0000 Subject: [PATCH 13/21] BUG#59177: mysqlbinlog_row_big fails on Windows with out of memory The test case fails with out of memory while updating a table with several multi-megabytes sized rows. This can probably be too exhausting for PB2 env. The quick fix here is to reduce the size of the biggest row (256MB) so that it becomes a little smaller (64MB). --- mysql-test/r/mysqlbinlog_row_big.result | 8 ++++---- mysql-test/t/mysqlbinlog_row_big.test | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/mysqlbinlog_row_big.result b/mysql-test/r/mysqlbinlog_row_big.result index 46fa0dc79cd..0bdbfdcee3a 100644 --- a/mysql-test/r/mysqlbinlog_row_big.result +++ b/mysql-test/r/mysqlbinlog_row_big.result @@ -36,8 +36,8 @@ c1 LONGTEXT # # Insert some big rows. # -256MB -INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 16777216)); +64MB +INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 4194304)); affected rows: 1 32MB INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 2097152)); @@ -53,7 +53,7 @@ affected rows: 1 # Do not display the column value itself, just its length. # SELECT LENGTH(c1) FROM t1; -LENGTH(c1) 268435456 +LENGTH(c1) 67108864 LENGTH(c1) 33554432 LENGTH(c1) 4194304 LENGTH(c1) 524288 @@ -69,7 +69,7 @@ info: Rows matched: 4 Changed: 4 Warnings: 0 # Do not display the column value itself, just its length. # SELECT LENGTH(c1) FROM t1; -LENGTH(c1) 536870912 +LENGTH(c1) 134217728 LENGTH(c1) 1048576 LENGTH(c1) 67108864 LENGTH(c1) 8388608 diff --git a/mysql-test/t/mysqlbinlog_row_big.test b/mysql-test/t/mysqlbinlog_row_big.test index 75f3b90269f..ffd1b79af34 100644 --- a/mysql-test/t/mysqlbinlog_row_big.test +++ b/mysql-test/t/mysqlbinlog_row_big.test @@ -79,8 +79,8 @@ eval CREATE TABLE t1 ( --echo # Insert some big rows. --echo # ---echo 256MB -INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 16777216)); +--echo 64MB +INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 4194304)); --echo 32MB INSERT INTO t1 VALUES (REPEAT('ManyMegaByteBlck', 2097152)); From 3e1ce666c48eca350c2625e5074e5049ae01eccb Mon Sep 17 00:00:00 2001 From: Ole John Aske Date: Thu, 13 Jan 2011 09:33:30 +0100 Subject: [PATCH 14/21] Fix for Bug#57034 incorrect OUTER JOIN result when joined on unique key Item_equal::val_int() checked for NULL-values by checking Item::null_value *before* the respective ::store_value() and ::cmp(Item*) metods where called. As Item::null_value is set by these metods, the value of 'null_value' is not valid until *after* ::store_value() or ::cmp() has been called for the Item object. Fix is to swap order of ::store_value()/::cmp() and checking of Item::null_value. This pattern is widely used other places inside item_cmpfunc.cc . --- mysql-test/r/join_outer.result | 70 +++++++++++++++++++++++++++++ mysql-test/t/join_outer.test | 82 ++++++++++++++++++++++++++++++++++ sql/item_cmpfunc.cc | 4 +- 3 files changed, 154 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 99ca9f05535..ecd53003513 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1432,4 +1432,74 @@ WHERE t1.f1 = 4 AND t2.f1 IS NOT NULL AND t2.f2 IS NOT NULL GROUP BY t2.f1, t2.f2; f1 f1 f2 DROP TABLE t1,t2; +# +# Bug#57034 incorrect OUTER JOIN result when joined on unique key +# +CREATE TABLE t1 (pk INT PRIMARY KEY, +col_int INT, +col_int_unique INT UNIQUE KEY); +INSERT INTO t1 VALUES (1,NULL,2), (2,0,0); +CREATE TABLE t2 (pk INT PRIMARY KEY, +col_int INT, +col_int_unique INT UNIQUE KEY); +INSERT INTO t2 VALUES (1,0,1), (2,0,2); +EXPLAIN +SELECT * FROM t1 LEFT JOIN t2 +ON t1.col_int_unique = t2.col_int_unique AND t1.col_int = t2.col_int +WHERE t1.pk=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t2 const col_int_unique col_int_unique 5 const 1 +SELECT * FROM t1 LEFT JOIN t2 +ON t1.col_int_unique = t2.col_int_unique AND t1.col_int = t2.col_int +WHERE t1.pk=1; +pk col_int col_int_unique pk col_int col_int_unique +1 NULL 2 NULL NULL NULL +DROP TABLE t1,t2; +# +# Bug#48046 Server incorrectly processing JOINs on NULL values +# +CREATE TABLE `BB` ( +`pk` int(11) NOT NULL AUTO_INCREMENT, +`time_key` time DEFAULT NULL, +`varchar_key` varchar(1) DEFAULT NULL, +`varchar_nokey` varchar(1) DEFAULT NULL, +PRIMARY KEY (`pk`), +KEY `time_key` (`time_key`), +KEY `varchar_key` (`varchar_key`) +) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1; +INSERT INTO `BB` VALUES (10,'18:27:58',NULL,NULL); +SELECT table1.time_key AS field1, table2.pk +FROM BB table1 LEFT JOIN BB table2 +ON table2.varchar_nokey = table1.varchar_key +HAVING field1; +field1 pk +18:27:58 NULL +DROP TABLE BB; +# +# Bug#49600 Server incorrectly processing RIGHT JOIN with +# constant WHERE clause and no index +# +CREATE TABLE `BB` ( +`col_datetime_key` datetime DEFAULT NULL, +`col_varchar_key` varchar(1) DEFAULT NULL, +`col_varchar_nokey` varchar(1) DEFAULT NULL, +KEY `col_datetime_key` (`col_datetime_key`), +KEY `col_varchar_key` (`col_varchar_key`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `BB` VALUES ('1900-01-01 00:00:00',NULL,NULL); +SELECT table1.col_datetime_key +FROM BB table1 RIGHT JOIN BB table2 +ON table2 .col_varchar_nokey = table1.col_varchar_key +WHERE 7; +col_datetime_key +NULL +ALTER TABLE BB DISABLE KEYS; +SELECT table1.col_datetime_key +FROM BB table1 RIGHT JOIN BB table2 +ON table2 .col_varchar_nokey = table1.col_varchar_key +WHERE 7; +col_datetime_key +NULL +DROP TABLE BB; End of 5.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 3251ff292b6..72d27d3571a 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1010,4 +1010,86 @@ GROUP BY t2.f1, t2.f2; DROP TABLE t1,t2; +--echo # +--echo # Bug#57034 incorrect OUTER JOIN result when joined on unique key +--echo # + +CREATE TABLE t1 (pk INT PRIMARY KEY, + col_int INT, + col_int_unique INT UNIQUE KEY); +INSERT INTO t1 VALUES (1,NULL,2), (2,0,0); + +CREATE TABLE t2 (pk INT PRIMARY KEY, + col_int INT, + col_int_unique INT UNIQUE KEY); +INSERT INTO t2 VALUES (1,0,1), (2,0,2); + +EXPLAIN +SELECT * FROM t1 LEFT JOIN t2 + ON t1.col_int_unique = t2.col_int_unique AND t1.col_int = t2.col_int + WHERE t1.pk=1; + +SELECT * FROM t1 LEFT JOIN t2 + ON t1.col_int_unique = t2.col_int_unique AND t1.col_int = t2.col_int + WHERE t1.pk=1; + +DROP TABLE t1,t2; + +--echo # +--echo # Bug#48046 Server incorrectly processing JOINs on NULL values +--echo # + +# bug#48046 is a duplicate of bug#57034 + +CREATE TABLE `BB` ( + `pk` int(11) NOT NULL AUTO_INCREMENT, + `time_key` time DEFAULT NULL, + `varchar_key` varchar(1) DEFAULT NULL, + `varchar_nokey` varchar(1) DEFAULT NULL, + PRIMARY KEY (`pk`), + KEY `time_key` (`time_key`), + KEY `varchar_key` (`varchar_key`) +) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1; + +INSERT INTO `BB` VALUES (10,'18:27:58',NULL,NULL); + +SELECT table1.time_key AS field1, table2.pk +FROM BB table1 LEFT JOIN BB table2 + ON table2.varchar_nokey = table1.varchar_key + HAVING field1; + +DROP TABLE BB; + +--echo # +--echo # Bug#49600 Server incorrectly processing RIGHT JOIN with +--echo # constant WHERE clause and no index +--echo # + +# bug#49600 is a duplicate of bug#57034 + +CREATE TABLE `BB` ( + `col_datetime_key` datetime DEFAULT NULL, + `col_varchar_key` varchar(1) DEFAULT NULL, + `col_varchar_nokey` varchar(1) DEFAULT NULL, + KEY `col_datetime_key` (`col_datetime_key`), + KEY `col_varchar_key` (`col_varchar_key`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +INSERT INTO `BB` VALUES ('1900-01-01 00:00:00',NULL,NULL); + +SELECT table1.col_datetime_key +FROM BB table1 RIGHT JOIN BB table2 + ON table2 .col_varchar_nokey = table1.col_varchar_key + WHERE 7; + +# Disable keys, and we get incorrect result for the same query +ALTER TABLE BB DISABLE KEYS; + +SELECT table1.col_datetime_key +FROM BB table1 RIGHT JOIN BB table2 + ON table2 .col_varchar_nokey = table1.col_varchar_key + WHERE 7; + +DROP TABLE BB; + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fe8ff3a74d0..ac13ca8a8c5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5643,15 +5643,15 @@ longlong Item_equal::val_int() return 0; List_iterator_fast it(fields); Item *item= const_item ? const_item : it++; + eval_item->store_value(item); if ((null_value= item->null_value)) return 0; - eval_item->store_value(item); while ((item_field= it++)) { /* Skip fields of non-const tables. They haven't been read yet */ if (item_field->field->table->const_table) { - if ((null_value= item_field->null_value) || eval_item->cmp(item_field)) + if (eval_item->cmp(item_field) || (null_value= item_field->null_value)) return 0; } } From ba38eef6dc48500182da039b77eb0ff51c52a087 Mon Sep 17 00:00:00 2001 From: Ole John Aske Date: Thu, 13 Jan 2011 10:20:45 +0100 Subject: [PATCH 15/21] Fix for bug#58134: 'Incorrectly condition pushdown inside subquery to NDB engine' An incorrect 'table_map' containing both the table itself, and possible any outer-refs if this was the last table in the subquery, was presented to make_cond_for_table(). As a pushed condition is only able to refer column from the table the condition is pushed to, nothing else than columns from the table itself (tab->table->map) may be refered in the pushed condition constructed by 'push_cond= make_cond_for_table()'. Also fix a minor 'copy and paste' bug in a comment inside make_cond_for_table(). No testcase is possible on mainbranch as the NDB engine is not available (yet) on mysql >= 5.5 --- sql/sql_select.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 91ce31636b4..26216225c3f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6480,7 +6480,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN) { COND *push_cond= - make_cond_for_table(tmp, current_map, current_map); + make_cond_for_table(tmp, tab->table->map, tab->table->map); if (push_cond) { /* Push condition to handler */ @@ -13099,7 +13099,7 @@ make_cond_for_table(COND *cond, table_map tables, table_map used_table) new_cond->argument_list()->push_back(fix); } /* - Item_cond_and do not need fix_fields for execution, its parameters + Item_cond_or do not need fix_fields for execution, its parameters are fixed or do not need fix_fields, too */ new_cond->quick_fix_field(); From 970c3fb244d07e019fb86dc660fcdd94e2174c82 Mon Sep 17 00:00:00 2001 From: Ole John Aske Date: Thu, 13 Jan 2011 11:42:48 +0100 Subject: [PATCH 16/21] Fix for #58422: Incorrect result when OUTER JOIN'ing with an empty table. Fixed incorrect checks in join_read_const_table() for when to accept a non-existing, or empty const-row as a part of the const'ified set of tables. Intention of this test is to only accept NULL-rows if this table is outer joined into the resultset. (In case of an inner-join we can conclude at this point that resultset will be empty, end we want to return 'error' to signal this.) Initially 'maybe_null' is set to the same value as 'outer_join' in setup_table_map(), mysql_priv.h ~line 2424. Later simplify_joins() will attemp to replace outer joins by inner join whenever possible. This will cause 'outer_join' to be updated. However, 'maybe_null' is *not* updated to reflect this rewrite as this field is used to currectly set the 'nullability' property for the columns in the resultset. We should therefore change join_read_const_table() to check the 'outer_join' property instead of 'maybe_null', as this correctly reflect the nullability of the *execution plan* (not *resultset*). --- mysql-test/r/select.result | 64 ++++++++++++++++++++++++++++++++++ mysql-test/t/select.test | 70 ++++++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 4 +-- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index a345a2ae6aa..af0ef29bb53 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4867,6 +4867,70 @@ SELECT 1 FROM t1 ORDER BY a COLLATE latin1_german2_ci; 1 1 DROP TABLE t1; +# +# Bug #58422: Incorrect result when OUTER JOIN'ing +# with an empty table +# +CREATE TABLE t_empty(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +CREATE TABLE t1(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +INSERT INTO t1 VALUES (1,1), (2,2), (3,3); +CREATE TABLE t2(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +INSERT INTO t2 VALUES (1,1), (2,2), (3,3); +EXPLAIN +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 INNER JOIN t_empty ON TRUE) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 INNER JOIN t_empty ON TRUE) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +pk i pk i pk i +EXPLAIN +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 CROSS JOIN t_empty) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 CROSS JOIN t_empty) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +pk i pk i pk i +EXPLAIN +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 INNER JOIN t_empty ON t_empty.i=t2.i) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT * +FROM +t1 +LEFT OUTER JOIN +(t2 INNER JOIN t_empty ON t_empty.i=t2.i) +ON t1.pk=t2.pk +WHERE t2.pk <> 2; +pk i pk i pk i +DROP TABLE t1,t2,t_empty; End of 5.1 tests # # Bug#54515: Crash in opt_range.cc::get_best_group_min_max on diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 3ed7213e8d7..043b03e4686 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -4123,6 +4123,76 @@ SELECT 1 FROM t1 ORDER BY a COLLATE latin1_german2_ci; DROP TABLE t1; + +--echo # +--echo # Bug #58422: Incorrect result when OUTER JOIN'ing +--echo # with an empty table +--echo # + +CREATE TABLE t_empty(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +CREATE TABLE t1(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +INSERT INTO t1 VALUES (1,1), (2,2), (3,3); +CREATE TABLE t2(pk INT PRIMARY KEY, i INT) ENGINE = MYISAM; +INSERT INTO t2 VALUES (1,1), (2,2), (3,3); + +EXPLAIN +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 INNER JOIN t_empty ON TRUE) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 INNER JOIN t_empty ON TRUE) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + + +EXPLAIN +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 CROSS JOIN t_empty) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 CROSS JOIN t_empty) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + + +EXPLAIN +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 INNER JOIN t_empty ON t_empty.i=t2.i) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + +SELECT * + FROM + t1 + LEFT OUTER JOIN + (t2 INNER JOIN t_empty ON t_empty.i=t2.i) + ON t1.pk=t2.pk + WHERE t2.pk <> 2; + + + +DROP TABLE t1,t2,t_empty; + + --echo End of 5.1 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 26216225c3f..fdce2510df4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12040,7 +12040,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; pos->ref_depend_map= 0; - if (!table->maybe_null || error > 0) + if (!table->pos_in_table_list->outer_join || error > 0) DBUG_RETURN(error); } } @@ -12061,7 +12061,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) /* Mark for EXPLAIN that the row was not found */ pos->records_read=0.0; pos->ref_depend_map= 0; - if (!table->maybe_null || error > 0) + if (!table->pos_in_table_list->outer_join || error > 0) DBUG_RETURN(error); } } From 7bee52da461873a229c6fc40eea0e7fed3c8f450 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 12 Jan 2011 18:36:39 -0200 Subject: [PATCH 17/21] Bug#42054: SELECT CURDATE() is returning bad value The problem from a user point of view was that on Solaris the time related functions (e.g. NOW(), SYSDATE(), etc) would always return a fixed time. This bug was happening due to a logic in the time retrieving wrapper function which would only call the time() function every half second. This interval between calls would be calculated using the gethrtime() and the logic relied on the fact that time returned by it is monotonic. Unfortunately, due to bugs in the gethrtime() implementation, there are some cases where the time returned by it can drift (See Solaris bug id 6600939), potentially causing the interval calculation logic to fail. Since newer versions of Solaris (10+) have alleviated the performance degradation associated with time(2), the solution is to simply directly rely on time() at each invocation. This simplification has an upside that it allows us to eliminate a lock which was used to control access to the variables used to track the half second interval, thus improving the overall scalability of timekeeping related functions (e.g. NOW()). Benchmarks runs have shown no significant degradation associated with this change. With this, there are actually improvements in performance for cases involving many connections. In summary, the changes introduced by this patch are: a) my_time() and my_micro_time_and_time() no longer use gethrtime(). Instead, time() and gettimeofdate() are used correspondingly. b) my_micro_time() is changed to not use gethrtime() so as to have the same time source as my_micro_time_and_time(). There shouldn't be any performance impact from this change since this function is used only a few times during statement execution and, on Solaris, gettimeofday() shows acceptable performance. --- .../suite/perfschema/r/server_init.result | 4 - .../suite/perfschema/t/server_init.test | 3 - mysys/my_getsystime.c | 140 ++++++------------ mysys/my_init.c | 3 +- mysys/my_thr_init.c | 4 +- mysys/mysys_priv.h | 4 +- 6 files changed, 52 insertions(+), 106 deletions(-) diff --git a/mysql-test/suite/perfschema/r/server_init.result b/mysql-test/suite/perfschema/r/server_init.result index b6f1d4828c3..26104197686 100644 --- a/mysql-test/suite/perfschema/r/server_init.result +++ b/mysql-test/suite/perfschema/r/server_init.result @@ -31,10 +31,6 @@ select count(name) from mutex_instances where name like "wait/synch/mutex/mysys/THR_LOCK_charset"; count(name) 1 -select count(name) from mutex_instances -where name like "wait/synch/mutex/mysys/THR_LOCK_time"; -count(name) -1 select count(name) from cond_instances where name like "wait/synch/cond/mysys/THR_COND_threads"; count(name) diff --git a/mysql-test/suite/perfschema/t/server_init.test b/mysql-test/suite/perfschema/t/server_init.test index 33eeeb7edb2..95d8be0e864 100644 --- a/mysql-test/suite/perfschema/t/server_init.test +++ b/mysql-test/suite/perfschema/t/server_init.test @@ -52,9 +52,6 @@ select count(name) from mutex_instances select count(name) from mutex_instances where name like "wait/synch/mutex/mysys/THR_LOCK_charset"; -select count(name) from mutex_instances - where name like "wait/synch/mutex/mysys/THR_LOCK_time"; - # There are no global rwlock in mysys # Verify that these global conditions have been properly initilized in mysys diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index 614f49fc425..01b3b912aae 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -25,13 +25,25 @@ #include "mysys_priv.h" #include "my_static.h" +/** + Get high-resolution time. + + @remark For windows platforms we need the frequency value of + the CPU. This is initialized in my_init.c through + QueryPerformanceFrequency(). If the Windows platform + doesn't support QueryPerformanceFrequency(), zero is + returned. + + @retval current high-resolution time. +*/ + ulonglong my_getsystime() { #ifdef HAVE_CLOCK_GETTIME struct timespec tp; clock_gettime(CLOCK_REALTIME, &tp); return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100; -#elif defined(__WIN__) +#elif defined(_WIN32) LARGE_INTEGER t_cnt; if (query_performance_frequency) { @@ -50,22 +62,17 @@ ulonglong my_getsystime() } -/* - Return current time +/** + Return current time. - SYNOPSIS - my_time() - flags If MY_WME is set, write error if time call fails + @param flags If MY_WME is set, write error if time call fails. + @retval current time. */ -time_t my_time(myf flags __attribute__((unused))) +time_t my_time(myf flags) { time_t t; -#ifdef HAVE_GETHRTIME - (void) my_micro_time_and_time(&t); - return t; -#else /* The following loop is here beacuse time() may fail on some systems */ while ((t= time(0)) == (time_t) -1) { @@ -73,39 +80,26 @@ time_t my_time(myf flags __attribute__((unused))) fprintf(stderr, "%s: Warning: time() call failed\n", my_progname); } return t; -#endif } -/* - Return time in micro seconds +/** + Return time in microseconds. - SYNOPSIS - my_micro_time() + @remark This function is to be used to measure performance in + micro seconds. As it's not defined whats the start time + for the clock, this function us only useful to measure + time between two moments. - NOTES - This function is to be used to measure performance in micro seconds. - As it's not defined whats the start time for the clock, this function - us only useful to measure time between two moments. - - For windows platforms we need the frequency value of the CUP. This is - initalized in my_init.c through QueryPerformanceFrequency(). - - If Windows platform doesn't support QueryPerformanceFrequency() we will - obtain the time via GetClockCount, which only supports milliseconds. - - RETURN - Value in microseconds from some undefined point in time + @retval Value in microseconds from some undefined point in time. */ ulonglong my_micro_time() { -#if defined(__WIN__) +#ifdef _WIN32 ulonglong newtime; GetSystemTimeAsFileTime((FILETIME*)&newtime); return (newtime/10); -#elif defined(HAVE_GETHRTIME) - return gethrtime()/1000; #else ulonglong newtime; struct timeval t; @@ -116,69 +110,37 @@ ulonglong my_micro_time() {} newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; return newtime; -#endif /* defined(__WIN__) */ +#endif } -/* +/** Return time in seconds and timer in microseconds (not different start!) - SYNOPSIS - my_micro_time_and_time() - time_arg Will be set to seconds since epoch (00:00:00 UTC, - January 1, 1970) + @param time_arg Will be set to seconds since epoch. - NOTES - This function is to be useful when we need both the time and microtime. - For example in MySQL this is used to get the query time start of a query - and to measure the time of a query (for the slow query log) + @remark This function is to be useful when we need both the time and + microtime. For example in MySQL this is used to get the query + time start of a query and to measure the time of a query (for + the slow query log) - IMPLEMENTATION - Value of time is as in time() call. - Value of microtime is same as my_micro_time(), which may be totally - unrealated to time() + @remark The time source is the same as for my_micro_time(), meaning + that time values returned by both functions can be intermixed + in meaningful ways (i.e. for comparison purposes). - RETURN - Value in microseconds from some undefined point in time + @retval Value in microseconds from some undefined point in time. */ -#define DELTA_FOR_SECONDS 500000000LL /* Half a second */ - /* Difference between GetSystemTimeAsFileTime() and now() */ #define OFFSET_TO_EPOCH 116444736000000000ULL ulonglong my_micro_time_and_time(time_t *time_arg) { -#if defined(__WIN__) +#ifdef _WIN32 ulonglong newtime; GetSystemTimeAsFileTime((FILETIME*)&newtime); *time_arg= (time_t) ((newtime - OFFSET_TO_EPOCH) / 10000000); return (newtime/10); -#elif defined(HAVE_GETHRTIME) - /* - Solaris has a very slow time() call. We optimize this by using the very - fast gethrtime() call and only calling time() every 1/2 second - */ - static hrtime_t prev_gethrtime= 0; - static time_t cur_time= 0; - hrtime_t cur_gethrtime; - - mysql_mutex_lock(&THR_LOCK_time); - cur_gethrtime= gethrtime(); - /* - Due to bugs in the Solaris (x86) implementation of gethrtime(), - the time returned by it might not be monotonic. Don't use the - cached time(2) value if this is a case. - */ - if ((prev_gethrtime > cur_gethrtime) || - ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS)) - { - cur_time= time(0); - prev_gethrtime= cur_gethrtime; - } - *time_arg= cur_time; - mysql_mutex_unlock(&THR_LOCK_time); - return cur_gethrtime/1000; #else ulonglong newtime; struct timeval t; @@ -190,37 +152,31 @@ ulonglong my_micro_time_and_time(time_t *time_arg) *time_arg= t.tv_sec; newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec; return newtime; -#endif /* defined(__WIN__) */ +#endif } -/* - Returns current time +/** + Returns current time. - SYNOPSIS - my_time_possible_from_micro() - microtime Value from very recent my_micro_time() + @param microtime Value from very recent my_micro_time(). - NOTES - This function returns the current time. The microtime argument is only used - if my_micro_time() uses a function that can safely be converted to the - current time. + @remark This function returns the current time. The microtime argument + is only used if my_micro_time() uses a function that can safely + be converted to the current time. - RETURN - current time + @retval current time. */ time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused))) { -#if defined(__WIN__) +#ifdef _WIN32 time_t t; while ((t= time(0)) == (time_t) -1) {} return t; -#elif defined(HAVE_GETHRTIME) - return my_time(0); /* Cached time */ #else return (time_t) (microtime / 1000000); -#endif /* defined(__WIN__) */ +#endif } diff --git a/mysys/my_init.c b/mysys/my_init.c index f5a2d9ac4bd..9a17d0d6916 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -510,7 +510,7 @@ PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap, key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc, key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, - key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time, + key_THR_LOCK_open, key_THR_LOCK_threads, key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap; static PSI_mutex_info all_mysys_mutexes[]= @@ -540,7 +540,6 @@ static PSI_mutex_info all_mysys_mutexes[]= { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL}, { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL}, { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL}, - { &key_THR_LOCK_time, "THR_LOCK_time", PSI_FLAG_GLOBAL}, { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL}, { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL} }; diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index c4b56cde850..a672d8af818 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -25,7 +25,7 @@ pthread_key(struct st_my_thread_var*, THR_KEY_mysys); mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_myisam, THR_LOCK_heap, - THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time, + THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_myisam_mmap; mysql_cond_t THR_COND_threads; @@ -219,7 +219,6 @@ my_bool my_thread_global_init(void) mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST); - mysql_mutex_init(key_THR_LOCK_time, &THR_LOCK_time, MY_MUTEX_INIT_FAST); mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL); #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) @@ -288,7 +287,6 @@ void my_thread_global_end(void) mysql_mutex_destroy(&THR_LOCK_myisam_mmap); mysql_mutex_destroy(&THR_LOCK_heap); mysql_mutex_destroy(&THR_LOCK_net); - mysql_mutex_destroy(&THR_LOCK_time); mysql_mutex_destroy(&THR_LOCK_charset); if (all_threads_killed) { diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 4e642b7e3d3..e760ea808b7 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -45,7 +45,7 @@ extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap, key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc, key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, - key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time, + key_THR_LOCK_open, key_THR_LOCK_threads, key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap; extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond, @@ -60,7 +60,7 @@ extern PSI_thread_key key_thread_alarm; extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net; -extern mysql_mutex_t THR_LOCK_charset, THR_LOCK_time; +extern mysql_mutex_t THR_LOCK_charset; #include From 3ef71bfac7ccdf7cb7a3d8f28a1695f0ea7be45f Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Thu, 13 Jan 2011 08:57:15 +0100 Subject: [PATCH 18/21] Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail and other crashes Some string manipulating SQL functions use a shared string object intended to contain an immutable empty string. This object was used by the SQL function SUBSTRING_INDEX() to return an empty string when one argument was of the wrong datatype. If the string object was then modified by the sql function INSERT(), undefined behavior ensued. Fixed by instead modifying the string object representing the function's result value whenever string manipulating SQL functions return an empty string. Relevant code has also been documented. --- mysql-test/r/func_str.result | 16 +++++++++++++ mysql-test/t/func_str.test | 11 +++++++++ sql/item_strfunc.cc | 45 ++++++++++++++++++------------------ sql/item_strfunc.h | 10 ++++++++ sql/sql_string.cc | 41 ++++++++++++++++++++++++++++---- sql/sql_string.h | 10 ++++++++ 6 files changed, 107 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 0321b2d85ad..8f4038e1239 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2612,4 +2612,20 @@ CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3)) 1 Warnings: Warning 1292 Truncated incorrect DECIMAL value: '' +# +# Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail +# and other crashes +# +CREATE TABLE t1 ( a TEXT ); +SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt'; +SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ); +insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ) +x +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'b' +LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1; +SELECT * FROM t1; +a +aaaaaaaaaaaaaa +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index fdcfbcf519e..92c4bae5327 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1369,4 +1369,15 @@ DROP TABLE t1; SELECT '1' IN ('1', SUBSTRING(-9223372036854775809, 1)); SELECT CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3)); +--echo # +--echo # Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail +--echo # and other crashes +--echo # +CREATE TABLE t1 ( a TEXT ); +SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt'; +SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ); +LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index fd5c47d25cb..204a2dfc663 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -39,6 +39,9 @@ C_MODE_START #include "../mysys/my_static.h" // For soundex_map C_MODE_END +/** + @todo Remove this. It is not safe to use a shared String object. + */ String my_empty_string("",default_charset_info); @@ -461,7 +464,7 @@ String *Item_func_des_encrypt::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) - return &my_empty_string; + return make_empty_result(); if (arg_count == 1) { @@ -652,7 +655,7 @@ String *Item_func_concat_ws::val_str(String *str) } if (i == arg_count) - return &my_empty_string; + return make_empty_result(); for (i++; i < arg_count ; i++) { @@ -803,7 +806,7 @@ String *Item_func_reverse::val_str(String *str) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return &my_empty_string; + return make_empty_result(); if (tmp_value.alloced_length() < res->length() && tmp_value.realloc(res->length())) { @@ -1143,8 +1146,7 @@ String *Item_func_left::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; - + return make_empty_result(); if ((res->length() <= (ulonglong) length) || (res->length() <= (char_pos= res->charpos((int) length)))) return res; @@ -1187,7 +1189,7 @@ String *Item_func_right::val_str(String *str) /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; /* purecov: inspected */ + return make_empty_result(); /* purecov: inspected */ if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ @@ -1226,7 +1228,7 @@ String *Item_func_substr::val_str(String *str) /* Negative or zero length, will return empty string. */ if ((arg_count == 3) && (length <= 0) && (length == 0 || !args[2]->unsigned_flag)) - return &my_empty_string; + return make_empty_result(); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -1237,12 +1239,12 @@ String *Item_func_substr::val_str(String *str) /* Assumes that the maximum length of a String is < INT_MAX32. */ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) - return &my_empty_string; + return make_empty_result(); start= ((start < 0) ? res->numchars() + start : start - 1); start= res->charpos((int) start); if ((start < 0) || ((uint) start + 1 > res->length())) - return &my_empty_string; + return make_empty_result(); length= res->charpos((int) length, (uint32) start); tmp_length= res->length() - start; @@ -1305,7 +1307,7 @@ String *Item_func_substr_index::val_str(String *str) null_value=0; uint delimiter_length= delimiter->length(); if (!res->length() || !delimiter_length || !count) - return &my_empty_string; // Wrong parameters + return make_empty_result(); // Wrong parameters res->set_charset(collation.collation); @@ -1654,7 +1656,7 @@ String *Item_func_password::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset()); return str; @@ -1678,7 +1680,7 @@ String *Item_func_old_password::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset()); return str; @@ -1706,8 +1708,7 @@ String *Item_func_encrypt::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; - + return make_empty_result(); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); @@ -1967,7 +1968,7 @@ String *Item_func_soundex::val_str(String *str) for ( ; ; ) /* Skip pre-space */ { if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0) - return &my_empty_string; /* EOL or invalid byte sequence */ + return make_empty_result(); /* EOL or invalid byte sequence */ if (rc == 1 && cs->ctype) { @@ -1992,7 +1993,7 @@ String *Item_func_soundex::val_str(String *str) { /* Extra safety - should not really happen */ DBUG_ASSERT(false); - return &my_empty_string; + return make_empty_result(); } to+= rc; break; @@ -2289,7 +2290,7 @@ String *Item_func_make_set::val_str(String *str) else { if (tmp_str.copy(*res)) // Don't use 'str' - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } } @@ -2299,11 +2300,11 @@ String *Item_func_make_set::val_str(String *str) { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) - return &my_empty_string; + return make_empty_result(); } } } @@ -2442,7 +2443,7 @@ String *Item_func_repeat::val_str(String *str) null_value= 0; if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) - return &my_empty_string; + return make_empty_result(); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Bounds check on count: If this is triggered, we will error. */ @@ -2750,7 +2751,7 @@ String *Item_func_conv::val_str(String *str) ptr= longlong2str(dec, ans, to_base); if (str->copy(ans, (uint32) (ptr-ans), default_charset())) - return &my_empty_string; + return make_empty_result(); return str; } @@ -2917,7 +2918,7 @@ String *Item_func_hex::val_str(String *str) return 0; ptr= longlong2str(dec,ans,16); if (str->copy(ans,(uint32) (ptr-ans),default_charset())) - return &my_empty_string; // End of memory + return make_empty_result(); // End of memory return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index ab2bf006032..6645a4c637a 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -22,6 +22,16 @@ class Item_str_func :public Item_func { +protected: + /** + Sets the result value of the function an empty string, using the current + character set. No memory is allocated. + @retval A pointer to the str_value member. + */ + String *make_empty_result() { + str_value.set("", 0, collation.collation); + return &str_value; + } public: Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; } Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index a41f4d52101..4f76943bde7 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -58,11 +58,33 @@ bool String::real_alloc(uint32 arg_length) } -/* -** Check that string is big enough. Set string[alloc_length] to 0 -** (for C functions) -*/ +/** + Allocates a new buffer on the heap for this String. + - If the String's internal buffer is privately owned and heap allocated, + one of the following is performed. + + - If the requested length is greater than what fits in the buffer, a new + buffer is allocated, data moved and the old buffer freed. + + - If the requested length is less or equal to what fits in the buffer, a + null character is inserted at the appropriate position. + + - If the String does not keep a private buffer on the heap, such a buffer + will be allocated and the string copied accoring to its length, as found + in String::length(). + + For C compatibility, the new string buffer is null terminated. + + @param alloc_length The requested string size in characters, excluding any + null terminator. + + @retval false Either the copy operation is complete or, if the size of the + new buffer is smaller than the currently allocated buffer (if one exists), + no allocation occured. + + @retval true An error occured when attempting to allocate memory. +*/ bool String::realloc(uint32 alloc_length) { uint32 len=ALIGN_SIZE(alloc_length+1); @@ -196,6 +218,17 @@ bool String::copy() return FALSE; } +/** + Copies the internal buffer from str. If this String has a private heap + allocated buffer where new data does not fit, a new buffer is allocated + before copying and the old buffer freed. Character set information is also + copied. + + @param str The string whose internal buffer is to be copied. + + @retval false Success. + @retval true Memory allocation failed. +*/ bool String::copy(const String &str) { if (alloc(str.str_length)) diff --git a/sql/sql_string.h b/sql/sql_string.h index b15179bcbe5..092e194646f 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -136,6 +136,16 @@ public: Alloced_length=0; str_charset=str.str_charset; } + + + /** + Points the internal buffer to the supplied one. The old buffer is freed. + @param str Pointer to the new buffer. + @param arg_length Length of the new buffer in characters, excluding any + null character. + @param cs Character set to use for interpreting string data. + @note The new buffer will not be null terminated. + */ inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); From 0355456dfbe077f55981bf03b9a1ce3c1622d3df Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 13 Jan 2011 10:57:19 +0200 Subject: [PATCH 19/21] bumped up the version to 5.0.93 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 21386494bda..fda56554879 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.92) +AM_INIT_AUTOMAKE(mysql, 5.0.93) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=92 +NDB_VERSION_BUILD=93 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From cbeb4e7630e7f8d961b3dbb6450c8cc7c160abfe Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Thu, 13 Jan 2011 15:56:42 +0530 Subject: [PATCH 20/21] Bug#59109 : mysqlslap crashes on mysql_fetch_row after ignoring null from mysql_store_result. mysqlslap segfaults at a point when it tries to fetch rows from the result set. Under some circumstances, mysql_store_result can return 'NULL', even after query execution (mysql_query) succeeds, and eventually a segfault might occur if same unchecked return value is passed to mysql_fetch_row. Fixed by adding a check on mysql_store_result's return value. --- client/mysqlslap.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/client/mysqlslap.c b/client/mysqlslap.c index b1eafe0082c..3b5c14dd74b 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1519,7 +1519,12 @@ generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt) exit(1); } - result= mysql_store_result(mysql); + if (!(result= mysql_store_result(mysql))) + { + fprintf(stderr, "%s: Error when storing result: %d %s\n", + my_progname, mysql_errno(mysql), mysql_error(mysql)); + exit(1); + } primary_keys_number_of= mysql_num_rows(result); /* So why check this? Blackhole :) */ @@ -1891,10 +1896,15 @@ limit_not_met: { if (mysql_field_count(mysql)) { - result= mysql_store_result(mysql); - while ((row = mysql_fetch_row(result))) - counter++; - mysql_free_result(result); + if (!(result= mysql_store_result(mysql))) + fprintf(stderr, "%s: Error when storing result: %d %s\n", + my_progname, mysql_errno(mysql), mysql_error(mysql)); + else + { + while ((row= mysql_fetch_row(result))) + counter++; + mysql_free_result(result); + } } } while(mysql_next_result(mysql) == 0); queries++; From cfa9a4bde6f519ed08b5791ba5f92c3f6da17c54 Mon Sep 17 00:00:00 2001 From: Serge Kozlov Date: Fri, 14 Jan 2011 00:18:17 +0300 Subject: [PATCH 21/21] Bug#54820: master_connect_retry increased for Valgrind environment support Bug#58525: separate string and numbers for comparing --- mysql-test/include/wait_for_status_var.inc | 22 +++++++- .../suite/rpl/r/rpl_heartbeat_basic.result | 46 ++++++++--------- .../suite/rpl/t/rpl_heartbeat_basic.test | 51 ++++++++++--------- 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/mysql-test/include/wait_for_status_var.inc b/mysql-test/include/wait_for_status_var.inc index 9f4962aeaed..5c68254f00e 100644 --- a/mysql-test/include/wait_for_status_var.inc +++ b/mysql-test/include/wait_for_status_var.inc @@ -50,8 +50,23 @@ if (!$_status_var_comparsion) let $_status_var_comparsion= =; } +# Get type of variable +let $_is_number= 0; +if (`SELECT '$status_var_value' REGEXP '^[\+\-]*[0-9]+(\.[0-9]+)*\$'`) +{ + let $_is_number= 1; +} + let $_show_status_value= query_get_value("SHOW $status_type STATUS LIKE '$status_var'", Value, 1); -while (`SELECT NOT('$_show_status_value' $_status_var_comparsion '$status_var_value')`) + +# Set way of comparing +let $_query= SELECT NOT('$_show_status_value' $_status_var_comparsion '$status_var_value'); +if ($is_number) +{ + let $_query= SELECT NOT($_show_status_value $_status_var_comparsion $status_var_value); +} + +while (`$_query`) { if (!$_status_timeout_counter) { @@ -65,4 +80,9 @@ while (`SELECT NOT('$_show_status_value' $_status_var_comparsion '$status_var_va dec $_status_timeout_counter; sleep 0.1; let $_show_status_value= query_get_value("SHOW $status_type STATUS LIKE '$status_var'", Value, 1); + let $_query= SELECT NOT('$_show_status_value' $_status_var_comparsion '$status_var_value'); + if ($is_number) + { + let $_query= SELECT NOT($_show_status_value $_status_var_comparsion $status_var_value); + } } diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result index ccef60d6323..ef901476784 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result @@ -16,7 +16,7 @@ RESET SLAVE; *** Reset slave affect *** SET @@global.slave_net_timeout=30; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=5; RESET SLAVE; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value @@ -24,7 +24,7 @@ Slave_heartbeat_period 15.000 *** Default value if slave_net_timeout changed *** SET @@global.slave_net_timeout=50; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root'; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value Slave_heartbeat_period 25.000 @@ -39,14 +39,14 @@ SET @@global.slave_net_timeout=@restore_slave_net_timeout; RESET SLAVE; *** Warning if updated slave_heartbeat_timeout > slave_net_timeout *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=SLAVE_NET_TIMEOUT; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=SLAVE_NET_TIMEOUT; Warnings: Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout. RESET SLAVE; *** CHANGE MASTER statement only updates slave_heartbeat_period *** SET @@global.slave_net_timeout=20; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=5; SHOW VARIABLES LIKE 'slave_net_timeout'; Variable_name Value slave_net_timeout 20 @@ -67,7 +67,7 @@ RESET SLAVE; SET @@global.slave_net_timeout=500; SET @@global.slave_net_timeout=200; RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root'; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20; include/start_slave.inc SHOW VARIABLES LIKE 'slave_net_timeout'; Variable_name Value @@ -82,7 +82,7 @@ SET @@global.slave_net_timeout=@restore_slave_net_timeout; *** Start/stop slave *** SET @@global.slave_net_timeout=100; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=20; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=20; include/start_slave.inc SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value @@ -94,7 +94,7 @@ Slave_heartbeat_period 20.000 *** Reload slave *** SET @@global.slave_net_timeout=50; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=30; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=30; include/rpl_restart_server.inc [server_number=2] SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value @@ -102,7 +102,7 @@ Slave_heartbeat_period 30.000 SET @restore_slave_net_timeout=@@global.slave_net_timeout; *** Disable heartbeat *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value Slave_heartbeat_period 0.000 @@ -129,12 +129,12 @@ Result 0 *** Min slave_heartbeat_timeout *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.001; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.001; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value Slave_heartbeat_period 0.001 RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.0009; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.0009; Warnings: Warning 1703 The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled. SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; @@ -143,36 +143,36 @@ Slave_heartbeat_period 0.000 RESET SLAVE; *** Max slave_heartbeat_timeout *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294967; Warnings: Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout. SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; Variable_name Value Slave_heartbeat_period 4294967.000 RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294968; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294968; ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds). RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=8589935; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=8589935; ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds). RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967296; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294967296; ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds). RESET SLAVE; *** Misc incorrect values *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='-1'; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD='-1'; 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 ''-1'' at line 1 RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='123abc'; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD='123abc'; 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 ''123abc'' at line 1 RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=''; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=''; 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 '''' at line 1 RESET SLAVE; *** Running slave *** -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.1; include/start_slave.inc Heartbeat event received @@ -218,7 +218,7 @@ BEGIN UPDATE test.t1 SET a = a + 1 WHERE a < 10; END| RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=5; include/start_slave.inc SET @@global.event_scheduler=1; Number of received heartbeat events: 0 @@ -231,7 +231,7 @@ RESET SLAVE; DROP TABLE t1; DROP TABLE t1; RESET MASTER; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.5; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.5; include/start_slave.inc Heartbeat events are received while rotation of relay logs (1 means 'yes'): 1 @@ -240,7 +240,7 @@ SET @@global.slave_compressed_protocol=1; include/stop_slave.inc RESET SLAVE; SET @@global.slave_compressed_protocol=1; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.1; include/start_slave.inc Heartbeat event received SET @@global.slave_compressed_protocol=0; @@ -249,7 +249,7 @@ SET @@global.slave_compressed_protocol=0; *** Reset master *** STOP SLAVE; RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.1; include/start_slave.inc RESET MASTER; Heartbeat events are received after reset of master (1 means 'yes'): 1 @@ -257,7 +257,7 @@ Heartbeat events are received after reset of master (1 means 'yes'): 1 *** Reload master *** STOP SLAVE; RESET SLAVE; -CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_CONNECT_RETRY = 5; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.1; include/start_slave.inc Heartbeat event received include/rpl_restart_server.inc [server_number=1] diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test index 94667485dfe..a89a1847bc6 100644 --- a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test @@ -18,6 +18,9 @@ --source include/have_binlog_format_mixed.inc --echo +# Set number of retries to connect to master +let $connect_retry= 20; + --echo *** Preparing *** --connection slave --source include/stop_slave.inc @@ -57,7 +60,7 @@ RESET SLAVE; SET @@global.slave_net_timeout=30; --enable_warnings --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; RESET SLAVE; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; --echo @@ -68,7 +71,7 @@ SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; SET @@global.slave_net_timeout=50; --enable_warnings --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; SET @@global.slave_net_timeout=@restore_slave_net_timeout; RESET SLAVE; @@ -88,7 +91,7 @@ RESET SLAVE; let $slave_net_timeout= query_get_value(SHOW VARIABLES LIKE 'slave_net_timeout', Value, 1); inc $slave_net_timeout; --replace_result $MASTER_MYPORT MASTER_PORT $slave_net_timeout SLAVE_NET_TIMEOUT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=$slave_net_timeout; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=$slave_net_timeout; RESET SLAVE; --echo @@ -98,7 +101,7 @@ RESET SLAVE; SET @@global.slave_net_timeout=20; --enable_warnings --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; SHOW VARIABLES LIKE 'slave_net_timeout'; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; SET @@global.slave_net_timeout=2*@@global.slave_net_timeout; @@ -118,7 +121,7 @@ SET @@global.slave_net_timeout=500; SET @@global.slave_net_timeout=200; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root'; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry; --source include/start_slave.inc --connection master --sync_slave_with_master @@ -138,7 +141,7 @@ SET @@global.slave_net_timeout=@restore_slave_net_timeout; SET @@global.slave_net_timeout=100; --enable_warnings --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=20; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=20; --source include/start_slave.inc --connection master --sync_slave_with_master @@ -154,7 +157,7 @@ SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; SET @@global.slave_net_timeout=50; --enable_warnings --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=30; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=30; --let $rpl_server_number= 2 --source include/rpl_restart_server.inc SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; @@ -164,7 +167,7 @@ SET @restore_slave_net_timeout=@@global.slave_net_timeout; # Disable heartbeat --echo *** Disable heartbeat *** --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; SHOW STATUS LIKE 'slave_received_heartbeats'; --source include/start_slave.inc @@ -188,48 +191,48 @@ let $slave_heartbeat_timeout= query_get_value(SHOW GLOBAL STATUS LIKE 'slave_hea --echo *** Min slave_heartbeat_timeout *** --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.001; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.001; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.0009; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.0009; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; RESET SLAVE; --echo --echo *** Max slave_heartbeat_timeout *** --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967; SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT --error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294968; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294968; RESET SLAVE; # Check double size of max allowed value for master_heartbeat_period --replace_result $MASTER_MYPORT MASTER_PORT --error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=8589935; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=8589935; RESET SLAVE; # Check 2^32 --replace_result $MASTER_MYPORT MASTER_PORT --error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=4294967296; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967296; RESET SLAVE; --echo --echo *** Misc incorrect values *** --replace_result $MASTER_MYPORT MASTER_PORT --error ER_PARSE_ERROR -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='-1'; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD='-1'; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT --error ER_PARSE_ERROR -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD='123abc'; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD='123abc'; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT --error ER_PARSE_ERROR -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=''; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=''; RESET SLAVE; --echo @@ -240,7 +243,7 @@ RESET SLAVE; # Check received heartbeat events for running slave --echo *** Running slave *** --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; --source include/start_slave.inc --connection master --sync_slave_with_master @@ -342,7 +345,7 @@ DELIMITER ;| --connection slave RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=5; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=5; --source include/start_slave.inc --connection master # Enable scheduler @@ -374,7 +377,7 @@ DROP TABLE t1; RESET MASTER; --connection slave --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.5; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.5; let $slave_param_comparison= =; --source include/start_slave.inc let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); @@ -401,7 +404,7 @@ SET @@global.slave_compressed_protocol=1; RESET SLAVE; SET @@global.slave_compressed_protocol=1; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; --source include/start_slave.inc let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); let $status_var= slave_received_heartbeats; @@ -420,7 +423,7 @@ SET @@global.slave_compressed_protocol=0; STOP SLAVE; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; --source include/start_slave.inc let $rcvd_heartbeats_before= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); --connection master @@ -439,7 +442,7 @@ let $result= query_get_value(SELECT ($rcvd_heartbeats_after - $rcvd_heartbeats_b STOP SLAVE; RESET SLAVE; --replace_result $MASTER_MYPORT MASTER_PORT -eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=0.1, MASTER_CONNECT_RETRY = 5; +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.1; --source include/start_slave.inc # Wait until slave_received_heartbeats will be incremented let $status_var_value= query_get_value(SHOW STATUS LIKE 'slave_received_heartbeats', Value, 1); @@ -474,7 +477,7 @@ let $status_var_comparsion= >; #let $slave_binlog= query_get_value(SHOW MASTER STATUS, File, 1); --connection master #--replace_result $SLAVE_MYPORT SLAVE_PORT $slave_binlog SLAVE_BINLOG -#eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$SLAVE_MYPORT, MASTER_USER='root', MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='$slave_binlog'; +#eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$SLAVE_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=1, MASTER_LOG_FILE='$slave_binlog'; --source include/start_slave.inc # Insert data on master and on slave and make sure that it replicated for both directions