From f60a8a680e717a53d78e873f29f7d70f8e60635e Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 9 Jan 2025 17:27:29 +1100 Subject: [PATCH 01/41] MDEV-35554 runtime error: call to function show_cached_thread_count() through pointer to incorrect function type. The argument is void* rather than char* and was missing system_status_var * as an argument. This shows up with UBSAN testing under clang. Reviewer: Brandon Nesterenko --- sql/mysqld.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c48f94e6601..c798956910f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7363,8 +7363,8 @@ static int show_threadpool_threads(THD *, SHOW_VAR *var, void *buff, #endif -static int show_cached_thread_count(THD *thd, SHOW_VAR *var, char *buff, - enum enum_var_type scope) +static int show_cached_thread_count(THD *thd, SHOW_VAR *var, void *buff, + system_status_var *, enum enum_var_type scope) { var->type= SHOW_LONG; var->value= buff; From d7f27d717287a385bc73a5d5950cc22f957fc152 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 9 Jan 2025 18:15:41 +1100 Subject: [PATCH 02/41] MDEV-33158: UBSAN via MYSQL_THDVAR_U{INT,LONG{,LONG}} In plugins, use the correct resolver for ULONG and ULONGLONG types. InnoDB has a UINT type as evidenced by "Unknown variable type code 0x182 in plugin 'InnoDB'." so the implementation for UNSIGNED INT was added. Any InnoDB mtr test that changes lock_wait_timeout, spider_param_force_commit and some MyRocks unsigned thread server variables can verify this change is correct. Reviewer: Brandon Nesterenko --- sql/sql_plugin.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 56c7b3332a2..360dc650334 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3227,6 +3227,11 @@ static int *mysql_sys_var_int(THD* thd, int offset) return (int *) intern_sys_var_ptr(thd, offset, true); } +static unsigned int *mysql_sys_var_uint(THD* thd, int offset) +{ + return (unsigned int *) intern_sys_var_ptr(thd, offset, true); +} + static long *mysql_sys_var_long(THD* thd, int offset) { return (long *) intern_sys_var_ptr(thd, offset, true); @@ -3897,19 +3902,28 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, continue; if (!(register_var(plugin_name_ptr, opt->name, opt->flags))) continue; - switch (opt->flags & PLUGIN_VAR_TYPEMASK) { + switch (opt->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) { case PLUGIN_VAR_BOOL: ((thdvar_bool_t *) opt)->resolve= mysql_sys_var_char; break; case PLUGIN_VAR_INT: ((thdvar_int_t *) opt)->resolve= mysql_sys_var_int; break; + case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED: + ((thdvar_uint_t *) opt)->resolve= mysql_sys_var_uint; + break; case PLUGIN_VAR_LONG: ((thdvar_long_t *) opt)->resolve= mysql_sys_var_long; break; + case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED: + ((thdvar_ulong_t *) opt)->resolve= mysql_sys_var_ulong; + break; case PLUGIN_VAR_LONGLONG: ((thdvar_longlong_t *) opt)->resolve= mysql_sys_var_longlong; break; + case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED: + ((thdvar_ulonglong_t *) opt)->resolve= mysql_sys_var_ulonglong; + break; case PLUGIN_VAR_STR: ((thdvar_str_t *) opt)->resolve= mysql_sys_var_str; break; From c3fd0f189a512b8775b72f2b3622bf7bea3a90aa Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 12 Jan 2025 12:33:34 +1100 Subject: [PATCH 03/41] MDEV-33158: UBSAN - plugin.cc partial move to C++ casts There were too many C casts rather than C++ casts here. Started a partial conversion covering within-file scoped changes. Suggested by Brandon Nesterenko --- sql/sql_plugin.cc | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 360dc650334..b773c8ec954 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3186,14 +3186,14 @@ void sync_dynamic_session_variables(THD* thd, bool global_lock) If required, will sync with global variables if the requested variable has not yet been allocated in the current thread. */ -static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) +static void *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) { DBUG_ENTER("intern_sys_var_ptr"); DBUG_ASSERT(offset >= 0); DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head); if (!thd) - DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset); + DBUG_RETURN(global_system_variables.dynamic_variables_ptr + offset); /* dynamic_variables_head points to the largest valid offset @@ -3205,7 +3205,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) sync_dynamic_session_variables(thd, global_lock); mysql_prlock_unlock(&LOCK_system_variables_hash); } - DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); + DBUG_RETURN(thd->variables.dynamic_variables_ptr + offset); } @@ -3219,47 +3219,47 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) static char *mysql_sys_var_char(THD* thd, int offset) { - return (char *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static int *mysql_sys_var_int(THD* thd, int offset) { - return (int *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static unsigned int *mysql_sys_var_uint(THD* thd, int offset) { - return (unsigned int *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static long *mysql_sys_var_long(THD* thd, int offset) { - return (long *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static unsigned long *mysql_sys_var_ulong(THD* thd, int offset) { - return (unsigned long *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static long long *mysql_sys_var_longlong(THD* thd, int offset) { - return (long long *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static unsigned long long *mysql_sys_var_ulonglong(THD* thd, int offset) { - return (unsigned long long *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static char **mysql_sys_var_str(THD* thd, int offset) { - return (char **) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } static double *mysql_sys_var_double(THD* thd, int offset) { - return (double *) intern_sys_var_ptr(thd, offset, true); + return static_cast(intern_sys_var_ptr(thd, offset, true)); } void plugin_thdvar_init(THD *thd) @@ -3520,7 +3520,7 @@ uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type) const if (type == OPT_GLOBAL) thd= NULL; - return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false); + return (uchar*) intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false); } return *(uchar**) (plugin_var+1); } @@ -3529,8 +3529,8 @@ uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type) const bool sys_var_pluginvar::session_is_default(THD *thd) { uchar *value= plugin_var->flags & PLUGIN_VAR_THDLOCAL - ? intern_sys_var_ptr(thd, *(int*) (plugin_var+1), true) - : *(uchar**) (plugin_var+1); + ? static_cast(intern_sys_var_ptr(thd, *(int*) (plugin_var+1), true)) + : *reinterpret_cast(plugin_var+1); real_value_ptr(thd, OPT_SESSION); @@ -3772,27 +3772,27 @@ void plugin_opt_set_limits(struct my_option *options, break; case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL: options->var_type= GET_ENUM; - options->typelib= ((thdvar_enum_t*) opt)->typelib; - options->def_value= ((thdvar_enum_t*) opt)->def_val; + options->typelib= reinterpret_cast(opt)->typelib; + options->def_value= reinterpret_cast(opt)->def_val; options->min_value= options->block_size= 0; options->max_value= options->typelib->count - 1; break; case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL: options->var_type= GET_SET; - options->typelib= ((thdvar_set_t*) opt)->typelib; - options->def_value= ((thdvar_set_t*) opt)->def_val; + options->typelib= reinterpret_cast(opt)->typelib; + options->def_value= reinterpret_cast(opt)->def_val; options->min_value= options->block_size= 0; options->max_value= (1ULL << options->typelib->count) - 1; break; case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL: options->var_type= GET_BOOL; - options->def_value= ((thdvar_bool_t*) opt)->def_val; + options->def_value= reinterpret_cast(opt)->def_val; options->typelib= &bool_typelib; break; case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL: options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ? GET_STR_ALLOC : GET_STR); - options->def_value= (intptr) ((thdvar_str_t*) opt)->def_val; + options->def_value= reinterpret_cast(reinterpret_cast(opt)->def_val); break; default: DBUG_ASSERT(0); @@ -3831,7 +3831,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, size_t plugin_name_len= strlen(plugin_name); size_t optnamelen; const int max_comment_len= 255; - char *comment= (char *) alloc_root(mem_root, max_comment_len + 1); + char *comment= static_cast(alloc_root(mem_root, max_comment_len + 1)); char *optname; int index= 0, UNINIT_VAR(offset); @@ -3843,7 +3843,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, DBUG_ENTER("construct_options"); - plugin_name_ptr= (char*) alloc_root(mem_root, plugin_name_len + 1); + plugin_name_ptr= static_cast(alloc_root(mem_root, plugin_name_len + 1)); safe_strcpy(plugin_name_ptr, plugin_name_len + 1, plugin_name); my_casedn_str(&my_charset_latin1, plugin_name_ptr); convert_underscore_to_dash(plugin_name_ptr, plugin_name_len); From cb26d41d8129b156e5ad4b0344790bd802a722c9 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 10 Jan 2025 12:59:01 +1100 Subject: [PATCH 04/41] MDEV-35735: UBSAN: spider udf functions mismatch with UDF defination The mismatch occurs on the function calls as in the sql/sql_udf.h the types of "error" and "is_null" are unsigned char rather than char. This is corrected for the udf functions: * spider_direct_sql * spider_direct_bg_sql * spider_flush_table_mon_cache * spider_copy_tables * spider_ping_table Reviewer: Yuchen Pei --- storage/spider/spd_copy_tables.cc | 4 ++-- storage/spider/spd_direct_sql.cc | 4 ++-- storage/spider/spd_ping_table.cc | 4 ++-- storage/spider/spd_udf.cc | 28 ++++++++++++++-------------- storage/spider/spd_udf.h | 12 ++++++------ 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/storage/spider/spd_copy_tables.cc b/storage/spider/spd_copy_tables.cc index 4c361df0562..d9cf32b3923 100644 --- a/storage/spider/spd_copy_tables.cc +++ b/storage/spider/spd_copy_tables.cc @@ -714,8 +714,8 @@ int spider_udf_bg_copy_exec_sql( long long spider_copy_tables_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { int error_num, roop_count, all_link_cnt = 0, use_table_charset; SPIDER_COPY_TABLES *copy_tables = NULL; diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc index 7c7f9aa7558..5aabb5c07fc 100644 --- a/storage/spider/spd_direct_sql.cc +++ b/storage/spider/spd_direct_sql.cc @@ -1225,8 +1225,8 @@ void spider_udf_free_direct_sql_alloc( long long spider_direct_sql_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error, + unsigned char *is_null, + unsigned char *error, my_bool bg ) { int error_num, roop_count; diff --git a/storage/spider/spd_ping_table.cc b/storage/spider/spd_ping_table.cc index 2795f8a3bb6..8e4f8a2214b 100644 --- a/storage/spider/spd_ping_table.cc +++ b/storage/spider/spd_ping_table.cc @@ -1071,8 +1071,8 @@ int spider_ping_table_cache_compare( long long spider_ping_table_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { int error_num = 0, link_idx, flags, full_mon_count, current_mon_count, success_count, fault_count, tmp_error_num = 0; diff --git a/storage/spider/spd_udf.cc b/storage/spider/spd_udf.cc index 023285cb4f1..fc7ca93c85b 100644 --- a/storage/spider/spd_udf.cc +++ b/storage/spider/spd_udf.cc @@ -22,8 +22,8 @@ extern "C" { long long spider_direct_sql( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { return spider_direct_sql_body(initid, args, is_null, error, FALSE); } @@ -46,8 +46,8 @@ void spider_direct_sql_deinit( long long spider_bg_direct_sql( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { return spider_direct_sql_bg_end(initid); } @@ -68,8 +68,8 @@ void spider_bg_direct_sql_deinit( void spider_bg_direct_sql_clear( UDF_INIT *initid, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { spider_direct_sql_bg_start(initid); } @@ -77,8 +77,8 @@ void spider_bg_direct_sql_clear( void spider_bg_direct_sql_add( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { spider_direct_sql_body(initid, args, is_null, error, TRUE); } @@ -87,8 +87,8 @@ void spider_bg_direct_sql_add( long long spider_ping_table( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { return spider_ping_table_body(initid, args, is_null, error); } @@ -110,8 +110,8 @@ void spider_ping_table_deinit( long long spider_flush_table_mon_cache( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { return spider_flush_table_mon_cache_body(); } @@ -132,8 +132,8 @@ void spider_flush_table_mon_cache_deinit( long long spider_copy_tables( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ) { return spider_copy_tables_body(initid, args, is_null, error); } diff --git a/storage/spider/spd_udf.h b/storage/spider/spd_udf.h index d00a6151894..a297640d945 100644 --- a/storage/spider/spd_udf.h +++ b/storage/spider/spd_udf.h @@ -16,8 +16,8 @@ long long spider_direct_sql_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error, + unsigned char *is_null, + unsigned char *error, my_bool bg ); @@ -45,8 +45,8 @@ long long spider_direct_sql_bg_end( long long spider_ping_table_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ); my_bool spider_ping_table_init_body( @@ -64,8 +64,8 @@ long long spider_flush_table_mon_cache_body(); long long spider_copy_tables_body( UDF_INIT *initid, UDF_ARGS *args, - char *is_null, - char *error + unsigned char *is_null, + unsigned char *error ); my_bool spider_copy_tables_init_body( From 6e86fe006399ca7f0a67cc5d4e0b9cfcf3cf63bb Mon Sep 17 00:00:00 2001 From: Xiaochuan Cui Date: Fri, 29 Nov 2024 13:52:19 -0800 Subject: [PATCH 05/41] MDEV-35528: mariadb-binlog cannot process more than 1 logfiles when --stop-datetime is specified Fix regression introduced by commits 9588526 which attempted to address MDEV-27037. With the regression, mariadb-binlog cannot process multiple log files when --stop-datetime is specified. The change is to keep recording timestamp of last processed event, and after all log files are processed, if the last recorded timestamp has not reached specified --stop-datetime, it will emit a warning. This applies when processing local log files, or log files from remote servers. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. Co-authored-by: Brandon Nesterenko Reviewed-by: Brandon Nesterenko --- client/mysqlbinlog.cc | 23 ++- ...nlog_mysqlbinlog_warn_stop_datetime.result | 136 +++++++++++++++--- ...nlog_mysqlbinlog_warn_stop_position.result | 76 ++++++++-- .../binlog_mysqlbinlog_warn_stop_datetime.inc | 106 ++++++++++++++ ...binlog_mysqlbinlog_warn_stop_datetime.test | 108 +++++++++----- .../binlog_mysqlbinlog_warn_stop_position.inc | 115 +++++++++++++++ ...binlog_mysqlbinlog_warn_stop_position.test | 93 +++++++++--- 7 files changed, 559 insertions(+), 98 deletions(-) create mode 100644 mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.inc create mode 100644 mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.inc diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 5762e3965b5..8e3ce812993 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -148,6 +148,8 @@ static const longlong stop_position_default= (longlong)(~(my_off_t)0); static char *start_datetime_str, *stop_datetime_str; static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX; +static my_time_t last_processed_datetime= MY_TIME_T_MAX; + static ulonglong rec_count= 0; static MYSQL* mysql = NULL; static const char* dirname_for_local_load= 0; @@ -1011,6 +1013,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, DBUG_ENTER("process_event"); Exit_status retval= OK_CONTINUE; IO_CACHE *const head= &print_event_info->head_cache; + my_time_t ev_when= ev->when; /* Bypass flashback settings to event */ ev->is_flashback= opt_flashback; @@ -1458,6 +1461,7 @@ err: retval= ERROR_STOP; end: rec_count++; + last_processed_datetime= ev_when; DBUG_PRINT("info", ("end event processing")); /* @@ -2847,7 +2851,6 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, IO_CACHE cache,*file= &cache; uchar tmp_buff[BIN_LOG_HEADER_SIZE]; Exit_status retval= OK_CONTINUE; - my_time_t last_ev_when= MY_TIME_T_MAX; if (logname && strcmp(logname, "-") != 0) { @@ -2953,21 +2956,8 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, "end of input", stop_position); } - /* - Emit a warning in the event that we finished processing input - before reaching the boundary indicated by --stop-datetime. - */ - if (stop_datetime != MY_TIME_T_MAX && - stop_datetime > last_ev_when) - { - retval = OK_STOP; - warning("Did not reach stop datetime '%s' " - "before end of input", stop_datetime_str); - } - goto end; } - last_ev_when= ev->when; if ((retval= process_event(print_event_info, ev, old_off, logname)) != OK_CONTINUE) goto end; @@ -3143,6 +3133,11 @@ int main(int argc, char** argv) start_position= BIN_LOG_HEADER_SIZE; } + if (stop_datetime != MY_TIME_T_MAX && + stop_datetime > last_processed_datetime) + warning("Did not reach stop datetime '%s' before end of input", + stop_datetime_str); + /* If enable flashback, need to print the events from the end to the beginning diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_datetime.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_datetime.result index 6ce0f2d63e5..88a3c6cc8ac 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_datetime.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_datetime.result @@ -1,23 +1,115 @@ - -# MDEV-27037 mysqlbinlog emits a warning when reaching EOF before stop-datetime - -set timestamp=1000000000; -CREATE TABLE t1(word VARCHAR(20)); -set timestamp=1000000010; -INSERT INTO t1 VALUES ("abirvalg"); -set timestamp=1000000020; -INSERT INTO t1 SELECT * FROM t1; -flush logs; -Case: Default, must not see warning. -# MYSQL_BINLOG --short-form MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file -Case: Stop datetime before EOF, must not see warning. -# MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:50' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file -Case: Stop datetime between records, must not see warning. -# MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file -Case: Stop datetime at EOF, must not see warning. -# MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file -Case: Stop datetime after EOF, must see warning. -# MYSQL_BINLOG --short-form --stop-datetime='2035-01-19 03:14:05' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file -WARNING: Did not reach stop datetime '2035-01-19 03:14:05' before end of input -DROP TABLE t1; +SET TIMESTAMP= UNIX_TIMESTAMP('2024-12-01 10:20:30.123456'); +# +# Clear the existing binary log state, and start fresh using +# the timestamp variable set above +# +RESET MASTER; +create table t1 (a int); +insert into t1 values (1); +SET TIMESTAMP= UNIX_TIMESTAMP('2024-12-02 10:20:30.123456'); +insert into t1 values (2); +SET TIMESTAMP= UNIX_TIMESTAMP('2024-12-03 10:20:30.123456'); +flush binary logs; +SET TIMESTAMP= UNIX_TIMESTAMP('2024-12-04 10:20:30.123456'); +insert into t1 values (3); +insert into t1 values (4); +SET TIMESTAMP= UNIX_TIMESTAMP('2024-12-05 10:20:30.123456'); +insert into t1 values (5); +insert into t1 values (6); +insert into t1 values (7); +SET TIMESTAMP=UNIX_TIMESTAMP('2024-12-06 10:20:30.123456'); +flush binary logs; +drop table t1; +# Ensuring binary log order is correct +# +# +# Test using --read-from-remote-server +# +connection default; +# +# --stop-datetime tests +# Note: MDEV-35528 reported that mysqlbinlog would fail on tests cases +# 2.a, 2.b, and 2.c. +# +# Case 1.a) With one binlog file, a --stop-datetime before the end of +# the file should not result in a warning +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-02 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +# +# Case 1.b) With one binlog file, a --stop-datetime at the end of the +# file should not result in a warning +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-03 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +# +# Case 1.c) With one binlog file, a --stop-datetime beyond the end of +# the file should(!) result in a warning +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-04 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +WARNING: Did not reach stop datetime '2024-12-04 10:20:30.123456' before end of input +# +# Case 2.a) With two binlog files, a --stop-datetime within the +# timespan of binlog 2 should: +# 1) not provide any warnings +# 2) not prevent binlog 1 or 2 from outputting the desired events +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-04 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +include/assert_grep.inc [Ensure all intended GTIDs are present] +include/assert_grep.inc [Ensure the next GTID binlogged is _not_ present] +# +# Case 2.b) With two binlog files, a --stop-datetime at the end of +# binlog 2 should: +# 1) not provide any warnings +# 2) not prevent binlog 1 or 2 from outputting all events +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-06 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# +# Case 2.c) With two binlog files, a --stop-datetime beyond the end of +# binlog 2 should: +# 1) provide a warning that the stop datetime was not reached +# 2) not prevent binlog 1 or 2 from outputting all events +# MYSQL_BINLOG --read-from-remote-server --stop-datetime='2024-12-07 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +WARNING: Did not reach stop datetime '2024-12-07 10:20:30.123456' before end of input +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# +# +# Test using local binlog files +# +connection default; +# +# --stop-datetime tests +# Note: MDEV-35528 reported that mysqlbinlog would fail on tests cases +# 2.a, 2.b, and 2.c. +# +# Case 1.a) With one binlog file, a --stop-datetime before the end of +# the file should not result in a warning +# MYSQL_BINLOG --stop-datetime='2024-12-02 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +# +# Case 1.b) With one binlog file, a --stop-datetime at the end of the +# file should not result in a warning +# MYSQL_BINLOG --stop-datetime='2024-12-03 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +# +# Case 1.c) With one binlog file, a --stop-datetime beyond the end of +# the file should(!) result in a warning +# MYSQL_BINLOG --stop-datetime='2024-12-04 10:20:30.123456' binlog_f1_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +WARNING: Did not reach stop datetime '2024-12-04 10:20:30.123456' before end of input +# +# Case 2.a) With two binlog files, a --stop-datetime within the +# timespan of binlog 2 should: +# 1) not provide any warnings +# 2) not prevent binlog 1 or 2 from outputting the desired events +# MYSQL_BINLOG --stop-datetime='2024-12-04 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +include/assert_grep.inc [Ensure all intended GTIDs are present] +include/assert_grep.inc [Ensure the next GTID binlogged is _not_ present] +# +# Case 2.b) With two binlog files, a --stop-datetime at the end of +# binlog 2 should: +# 1) not provide any warnings +# 2) not prevent binlog 1 or 2 from outputting all events +# MYSQL_BINLOG --stop-datetime='2024-12-06 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# +# Case 2.c) With two binlog files, a --stop-datetime beyond the end of +# binlog 2 should: +# 1) provide a warning that the stop datetime was not reached +# 2) not prevent binlog 1 or 2 from outputting all events +# MYSQL_BINLOG --stop-datetime='2024-12-07 10:20:30.123456' binlog_f1_full binlog_f2_full --result-file=tmp/warn_datetime_test_file.out 2>&1 +WARNING: Did not reach stop datetime '2024-12-07 10:20:30.123456' before end of input +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# # End of binlog_mysqlbinlog_warn_stop_datetime.test diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result index 5b99d30bd84..1517fd765ac 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_warn_stop_position.result @@ -1,13 +1,65 @@ - -# MDEV-27037 mysqlbinlog emits a warning when reaching EOF before stop-condition - -Case: Default stop position, WARNING must not appear -# MYSQL_BINLOG --short-form --start-position=4 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 -Case: Stop position before EOF, WARNING must not appear -# MYSQL_BINLOG --short-form --start-position=4 --stop-position=97 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 -Case: Stop position at EOF, WARNING must not appear -# MYSQL_BINLOG --short-form --start-position=4 --stop-position=98 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 -Case: Stop position after EOF, WARNING must appear -# MYSQL_BINLOG --short-form --start-position=4 --stop-position=99 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 -WARNING: Did not reach stop position 99 before end of input +# +# Clear the existing binary log state. +# +RESET MASTER; +create table t1 (a int); +insert into t1 values (1); +insert into t1 values (2); +flush binary logs; +insert into t1 values (3); +# Tag binlog_f2_mid +insert into t1 values (4); +insert into t1 values (5); +insert into t1 values (6); +insert into t1 values (7); +flush binary logs; +drop table t1; +# Ensuring binary log order is correct +# Ensuring file offset of binlog_f2_mid < binlog_f1_end +# +# +# Test using local binlog files +# +connection default; +# +# --stop-position tests +# +# Case 1.a) With one binlog file, a --stop-position before the end of +# the file should not result in a warning +# MYSQL_BINLOG --stop-position=binlog_f1_pre_rotate binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +# +# Case 1.b) With one binlog file, a --stop-position at the exact end of +# the file should not result in a warning +# MYSQL_BINLOG --stop-position=binlog_f1_end binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +# +# Case 1.c) With one binlog file, a --stop-position past the end of the +# file should(!) result in a warning +# MYSQL_BINLOG --short-form --stop-position=binlog_f1_over_eof binlog_f1_full --result-file=tmp/warn_position_test_file.out 2>&1 +WARNING: Did not reach stop position before end of input +# +# Case 2.a) With two binlog files, a --stop-position targeting b2 which +# exists in the size of b1 should: +# 1) not provide any warnings +# 2) not prevent b2 from outputting its desired events before the +# stop position +# MYSQL_BINLOG --stop-position=binlog_f2_mid binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +include/assert_grep.inc [Ensure all intended GTIDs are present] +include/assert_grep.inc [Ensure the next GTID binlogged is _not_ present] +# +# Case 2.b) With two binlog files, a --stop-position targeting the end +# of binlog 2 should: +# 1) not provide any warnings +# 2) not prevent b2 from outputting its entire binary log +# MYSQL_BINLOG --stop-position=binlog_f2_end binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +include/assert_grep.inc [Ensure a GTID exists for each transaction] +include/assert_grep.inc [Ensure the last GTID binlogged is present] +# +# Case 2.c) With two binlog files, a --stop-position targeting beyond +# the eof of binlog 2 should: +# 1) provide a warning that the stop position was not reached +# 2) not prevent b2 from outputting its entire binary log +# MYSQL_BINLOG --stop-position=binlog_f2_over_eof binlog_f1_full binlog_f2_full --result-file=tmp/warn_position_test_file.out 2>&1 +WARNING: Did not reach stop position before end of input +include/assert_grep.inc [Ensure a GTID exists for each transaction] +# # End of binlog_mysqlbinlog_warn_stop_position.test diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.inc b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.inc new file mode 100644 index 00000000000..839e506551c --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.inc @@ -0,0 +1,106 @@ +# +# Helper file that ensures mysqlbinlog --stop-datetime behavior for local +# files or a remote server +# +# Parameters: +# read_from_remote_server (bool): A boolean that changes which source to use +# for mysqlbinlog. When true, reads remotely; when false, uses local files. +# + +--connection default +--let $MYSQLD_DATADIR= `select @@datadir` + +# PARAM_READ_FROM_REMOTE is used as a parameter to mysqlbinlog (_OUT suffix is +# output in echo commands). If using local files, they are blank; if reading +# from remote server, it is overridden to the correct values. +--let $PARAM_READ_FROM_REMOTE= +# Used in echo statements to remove potentially changing values +--let $PARAM_READ_FROM_REMOTE_OUT= + +if ($read_from_remote_server) +{ + --let $PARAM_READ_FROM_REMOTE= --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT + --let $PARAM_READ_FROM_REMOTE_OUT= --read-from-remote-server + # binlog files in --read-from-remote-server don't use file system path + --let $binlog_f1_full= $binlog_f1 + --let $binlog_f2_full= $binlog_f2 +} +if (!$read_from_remote_server) +{ + # If using local files, file system path to the binlog files is needed + --let $binlog_f1_full= $MYSQLD_DATADIR/$binlog_f1 + --let $binlog_f2_full= $MYSQLD_DATADIR/$binlog_f2 +} + +--echo # +--echo # --stop-datetime tests +--echo # Note: MDEV-35528 reported that mysqlbinlog would fail on tests cases +--echo # 2.a, 2.b, and 2.c. +--echo # + +--echo # Case 1.a) With one binlog file, a --stop-datetime before the end of +--echo # the file should not result in a warning +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b1_timestamp2' binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b1_timestamp2' $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 1.b) With one binlog file, a --stop-datetime at the end of the +--echo # file should not result in a warning +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b1_timestamp3' binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b1_timestamp3' $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 1.c) With one binlog file, a --stop-datetime beyond the end of +--echo # the file should(!) result in a warning +--let $future_timestamp= 2035-12-06 10:20:30.123456 +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b2_timestamp1' binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b2_timestamp1' $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 2.a) With two binlog files, a --stop-datetime within the +--echo # timespan of binlog 2 should: +--echo # 1) not provide any warnings +--echo # 2) not prevent binlog 1 or 2 from outputting the desired events + +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b2_timestamp1' binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b2_timestamp1' $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $server_id= `SELECT @@GLOBAL.server_id` +--let $domain_id= `SELECT @@GLOBAL.gtid_domain_id` +--let $assert_file= $binlog_out +--let $assert_text= Ensure all intended GTIDs are present +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 3 +--source include/assert_grep.inc + +--let $assert_text= Ensure the next GTID binlogged is _not_ present +--let $assert_select= GTID $binlog_f2_gtid_after_midpoint +--let $assert_count= 0 +--source include/assert_grep.inc + +--echo # +--echo # Case 2.b) With two binlog files, a --stop-datetime at the end of +--echo # binlog 2 should: +--echo # 1) not provide any warnings +--echo # 2) not prevent binlog 1 or 2 from outputting all events +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b2_timestamp3' binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b2_timestamp3' $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $assert_text= Ensure a GTID exists for each transaction +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 8 +--source include/assert_grep.inc + +--echo # +--echo # Case 2.c) With two binlog files, a --stop-datetime beyond the end of +--echo # binlog 2 should: +--echo # 1) provide a warning that the stop datetime was not reached +--echo # 2) not prevent binlog 1 or 2 from outputting all events +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-datetime='$b2_timestamp_not_reached' binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-datetime='$b2_timestamp_not_reached' $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $assert_text= Ensure a GTID exists for each transaction +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 8 +--source include/assert_grep.inc + diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.test index 9d30544c5f4..f862f0e7887 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_datetime.test @@ -1,42 +1,86 @@ ---echo ---echo # MDEV-27037 mysqlbinlog emits a warning when reaching EOF before stop-datetime ---echo +# +# Test ensures that --stop-datetime work correctly for mysqlbinlog. This high +# level test sets up the binary log (and tags certain locations for comparison), +# and the helper file binlog_mysqlbinlog_warn_stop_datetime.inc performs the +# actual tests. +# +# References: +# MDEV-27037: mysqlbinlog emits a warning when reaching EOF before +# stop-condition +# MDEV-35528: mariadb-binlog cannot process more than 1 logfiles when +# --stop-datetime is specified +# +--source include/have_log_bin.inc ---source include/have_binlog_format_statement.inc +--let $binlog_out_relpath= tmp/warn_datetime_test_file.out +--let $binlog_out= $MYSQLTEST_VARDIR/$binlog_out_relpath ---let ignored_output_file= $MYSQLTEST_VARDIR/tmp/warn_pos_test_file.out +--let $b1_timestamp1= 2024-12-01 10:20:30.123456 +--let $b1_timestamp2= 2024-12-02 10:20:30.123456 +--let $b1_timestamp3= 2024-12-03 10:20:30.123456 +--let $b2_timestamp1= 2024-12-04 10:20:30.123456 +--let $b2_timestamp2= 2024-12-05 10:20:30.123456 +--let $b2_timestamp3= 2024-12-06 10:20:30.123456 +--let $b2_timestamp_not_reached= 2024-12-07 10:20:30.123456 -set timestamp=1000000000; -CREATE TABLE t1(word VARCHAR(20)); -set timestamp=1000000010; -INSERT INTO t1 VALUES ("abirvalg"); -set timestamp=1000000020; -INSERT INTO t1 SELECT * FROM t1; ---let MYSQLD_DATADIR= `select @@datadir;` -flush logs; +--eval SET TIMESTAMP= UNIX_TIMESTAMP('$b1_timestamp1') ---echo Case: Default, must not see warning. ---echo # MYSQL_BINLOG --short-form MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file ---exec $MYSQL_BINLOG --short-form $MYSQLD_DATADIR/master-bin.000001 --result-file=$ignored_output_file 2>&1 +--echo # +--echo # Clear the existing binary log state, and start fresh using +--echo # the timestamp variable set above +--echo # +RESET MASTER; ---echo Case: Stop datetime before EOF, must not see warning. ---echo # MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:50' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file ---exec $MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:50' $MYSQLD_DATADIR/master-bin.000001 --result-file=$ignored_output_file 2>&1 +--let $binlog_f1= query_get_value(SHOW MASTER STATUS, File, 1) +create table t1 (a int); +insert into t1 values (1); +--eval SET TIMESTAMP= UNIX_TIMESTAMP('$b1_timestamp2') +insert into t1 values (2); +--eval SET TIMESTAMP= UNIX_TIMESTAMP('$b1_timestamp3') +flush binary logs; +--let $binlog_f2= query_get_value(SHOW MASTER STATUS, File, 1) +--eval SET TIMESTAMP= UNIX_TIMESTAMP('$b2_timestamp1') +insert into t1 values (3); +insert into t1 values (4); +--eval SET TIMESTAMP= UNIX_TIMESTAMP('$b2_timestamp2') +--let $binlog_f2_gtid_after_midpoint= `SELECT @@GLOBAL.gtid_binlog_pos` +insert into t1 values (5); +insert into t1 values (6); +insert into t1 values (7); +--let $binlog_f2_last_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` +--eval SET TIMESTAMP=UNIX_TIMESTAMP('$b2_timestamp3') +flush binary logs; +drop table t1; ---echo Case: Stop datetime between records, must not see warning. ---echo # MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file ---exec $MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' $MYSQLD_DATADIR/master-bin.000001 --result-file=$ignored_output_file 2>&1 +--echo # Ensuring binary log order is correct +--let $binlog_f1_show= query_get_value(SHOW BINARY LOGS, Log_name, 1) +if (`SELECT strcmp('$binlog_f1','$binlog_f1_show') != 0`) +{ + --echo # Real binlog_f1: $binlog_f1 + --echo # First binlog in SHOW BINLOG FILES: $binlog_f1_show + --die Wrong order of binary log files in SHOW BINARY LOGS +} +--let $binlog_f2_show= query_get_value(SHOW BINARY LOGS, Log_name, 2) +if (`SELECT strcmp('$binlog_f2','$binlog_f2_show') != 0`) +{ + --echo # Real binlog_f2: $binlog_f2 + --echo # First binlog in SHOW BINLOG FILES: $binlog_f2_show + --die Wrong order of binary log files in SHOW BINARY LOGS +} ---echo Case: Stop datetime at EOF, must not see warning. ---echo # MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file ---exec $MYSQL_BINLOG --short-form --stop-datetime='2001-09-08 21:46:55' $MYSQLD_DATADIR/master-bin.000001 --result-file=$ignored_output_file 2>&1 +--echo # +--echo # +--echo # Test using --read-from-remote-server +--echo # +--let $read_from_remote_server= 1 +--source binlog_mysqlbinlog_warn_stop_datetime.inc ---echo Case: Stop datetime after EOF, must see warning. ---echo # MYSQL_BINLOG --short-form --stop-datetime='2035-01-19 03:14:05' MYSQLD_DATADIR/master-bin.000001 --result-file=ignored_output_file ---exec $MYSQL_BINLOG --short-form --stop-datetime='2035-01-19 03:14:05' $MYSQLD_DATADIR/master-bin.000001 --result-file=$ignored_output_file 2>&1 - -DROP TABLE t1; - ---remove_file $ignored_output_file +--echo # +--echo # +--echo # Test using local binlog files +--echo # +--let $read_from_remote_server= 0 +--source binlog_mysqlbinlog_warn_stop_datetime.inc +--echo # --echo # End of binlog_mysqlbinlog_warn_stop_datetime.test diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.inc b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.inc new file mode 100644 index 00000000000..2c3c565d692 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.inc @@ -0,0 +1,115 @@ +# +# Helper file that ensures mysqlbinlog --stop-position behavior for local +# files or a remote server +# +# Parameters: +# read_from_remote_server (bool): A boolean that changes which source to use +# for mysqlbinlog. When true, reads remotely; when false, uses local files. +# + +--connection default +--let $MYSQLD_DATADIR= `select @@datadir` + +# PARAM_READ_FROM_REMOTE is used as a parameter to mysqlbinlog (_OUT suffix is +# output in echo commands). If using local files, they are blank; if reading +# from remote server, it is overridden to the correct values. +--let $PARAM_READ_FROM_REMOTE= +# Used in echo statements to remove potentially changing values +--let $PARAM_READ_FROM_REMOTE_OUT= + +if ($read_from_remote_server) +{ + --let $PARAM_READ_FROM_REMOTE= --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT + --let $PARAM_READ_FROM_REMOTE_OUT= --read-from-remote-server + # binlog files in --read-from-remote-server don't use file system path + --let $binlog_f1_full= $binlog_f1 + --let $binlog_f2_full= $binlog_f2 +} +if (!$read_from_remote_server) +{ + # If using local files, file system path to the binlog files is needed + --let $binlog_f1_full= $MYSQLD_DATADIR/$binlog_f1 + --let $binlog_f2_full= $MYSQLD_DATADIR/$binlog_f2 +} + +--echo # +--echo # --stop-position tests +--echo # + +--echo # Case 1.a) With one binlog file, a --stop-position before the end of +--echo # the file should not result in a warning +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-position=binlog_f1_pre_rotate binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-position=$binlog_f1_pre_rotate $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 1.b) With one binlog file, a --stop-position at the exact end of +--echo # the file should not result in a warning +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-position=binlog_f1_end binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-position=$binlog_f1_end $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 1.c) With one binlog file, a --stop-position past the end of the +--echo # file should(!) result in a warning +--let $binlog_f1_over_eof= `SELECT $binlog_f1_end + 1` +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --short-form --stop-position=binlog_f1_over_eof binlog_f1_full --result-file=$binlog_out_relpath 2>&1 +--replace_result $binlog_f1_over_eof +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --short-form --stop-position=$binlog_f1_over_eof $binlog_f1_full --result-file=$binlog_out 2>&1 + +--echo # +--echo # Case 2.a) With two binlog files, a --stop-position targeting b2 which +--echo # exists in the size of b1 should: +--echo # 1) not provide any warnings +--echo # 2) not prevent b2 from outputting its desired events before the +--echo # stop position +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-position=binlog_f2_mid binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-position=$binlog_f2_mid $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $server_id= `SELECT @@GLOBAL.server_id` +--let $domain_id= `SELECT @@GLOBAL.gtid_domain_id` +--let $assert_file= $binlog_out +--let $assert_text= Ensure all intended GTIDs are present +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 4 +--source include/assert_grep.inc + +--let $assert_text= Ensure the next GTID binlogged is _not_ present +--let $assert_select= GTID $binlog_f2_gtid_after_midpoint +--let $assert_count= 0 +--source include/assert_grep.inc + +--echo # +--echo # Case 2.b) With two binlog files, a --stop-position targeting the end +--echo # of binlog 2 should: +--echo # 1) not provide any warnings +--echo # 2) not prevent b2 from outputting its entire binary log +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-position=binlog_f2_end binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-position=$binlog_f2_end $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $server_id= `SELECT @@GLOBAL.server_id` +--let $domain_id= `SELECT @@GLOBAL.gtid_domain_id` +--let $assert_text= Ensure a GTID exists for each transaction +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 8 +--source include/assert_grep.inc + +--let $assert_text= Ensure the last GTID binlogged is present +--let $assert_select= GTID $binlog_f2_last_gtid +--let $assert_count= 1 +--source include/assert_grep.inc + +--echo # +--echo # Case 2.c) With two binlog files, a --stop-position targeting beyond +--echo # the eof of binlog 2 should: +--echo # 1) provide a warning that the stop position was not reached +--echo # 2) not prevent b2 from outputting its entire binary log +--let $binlog_f2_over_eof= `SELECT $binlog_f2_end + 1` +--echo # MYSQL_BINLOG $PARAM_READ_FROM_REMOTE_OUT --stop-position=binlog_f2_over_eof binlog_f1_full binlog_f2_full --result-file=$binlog_out_relpath 2>&1 +--replace_result $binlog_f2_over_eof +--exec $MYSQL_BINLOG $PARAM_READ_FROM_REMOTE --stop-position=$binlog_f2_over_eof $binlog_f1_full $binlog_f2_full --result-file=$binlog_out 2>&1 + +--let $server_id= `SELECT @@GLOBAL.server_id` +--let $domain_id= `SELECT @@GLOBAL.gtid_domain_id` +--let $assert_text= Ensure a GTID exists for each transaction +--let $assert_select= GTID $domain_id-$server_id- +--let $assert_count= 8 +--source include/assert_grep.inc diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test index 97fabfc6513..a9179297220 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_warn_stop_position.test @@ -1,26 +1,83 @@ ---echo ---echo # MDEV-27037 mysqlbinlog emits a warning when reaching EOF before stop-condition ---echo +# +# Test ensures that --stop-position work correctly for mysqlbinlog. This high +# level test sets up the binary log (and tags certain locations for comparison), +# and the helper file binlog_mysqlbinlog_warn_stop_position.inc performs the +# actual tests. +# +# References: +# MDEV-27037: mysqlbinlog emits a warning when reaching EOF before +# stop-condition +# +--source include/have_log_bin.inc ---let assert_file= $MYSQLTEST_VARDIR/tmp/warn_pos_test_file.out ---let data_file= $MYSQLTEST_VARDIR/std_data/master-bin.000001 +--let $binlog_out_relpath= tmp/warn_position_test_file.out +--let $binlog_out= $MYSQLTEST_VARDIR/$binlog_out_relpath ---echo Case: Default stop position, WARNING must not appear ---echo # MYSQL_BINLOG --short-form --start-position=4 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 ---exec $MYSQL_BINLOG --short-form --start-position=4 $data_file --result-file=$assert_file 2>&1 +--echo # +--echo # Clear the existing binary log state. +--echo # +RESET MASTER; ---echo Case: Stop position before EOF, WARNING must not appear ---echo # MYSQL_BINLOG --short-form --start-position=4 --stop-position=97 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 ---exec $MYSQL_BINLOG --short-form --start-position=4 --stop-position=97 $data_file --result-file=$assert_file 2>&1 +--let $binlog_f1= query_get_value(SHOW MASTER STATUS, File, 1) +create table t1 (a int); +insert into t1 values (1); +insert into t1 values (2); +--let $binlog_f1_pre_rotate= query_get_value(SHOW MASTER STATUS, Position, 1) +flush binary logs; +--let $binlog_f2= query_get_value(SHOW MASTER STATUS, File, 1) +insert into t1 values (3); +--echo # Tag binlog_f2_mid +--let $binlog_f2_mid= query_get_value(SHOW MASTER STATUS, Position, 1) +insert into t1 values (4); +--let $binlog_f2_gtid_after_midpoint= `SELECT @@GLOBAL.gtid_binlog_pos` +insert into t1 values (5); +insert into t1 values (6); +insert into t1 values (7); +--let $binlog_f2_last_gtid= `SELECT @@GLOBAL.gtid_binlog_pos` +--let $binlog_f2_pre_rot= query_get_value(SHOW MASTER STATUS, Position, 1) +flush binary logs; +drop table t1; ---echo Case: Stop position at EOF, WARNING must not appear ---echo # MYSQL_BINLOG --short-form --start-position=4 --stop-position=98 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 ---exec $MYSQL_BINLOG --short-form --start-position=4 --stop-position=98 $data_file --result-file=$assert_file 2>&1 +--echo # Ensuring binary log order is correct +--let $binlog_f1_show= query_get_value(SHOW BINARY LOGS, Log_name, 1) +--let $binlog_f1_end= query_get_value(SHOW BINARY LOGS, File_size, 1) +if (`SELECT strcmp('$binlog_f1','$binlog_f1_show') != 0`) +{ + --echo # Real binlog_f1: $binlog_f1 + --echo # First binlog in SHOW BINLOG FILES: $binlog_f1_show + --die Wrong order of binary log files in SHOW BINARY LOGS +} +--let $binlog_f2_show= query_get_value(SHOW BINARY LOGS, Log_name, 2) +--let $binlog_f2_end= query_get_value(SHOW BINARY LOGS, File_size, 2) +if (`SELECT strcmp('$binlog_f2','$binlog_f2_show') != 0`) +{ + --echo # Real binlog_f2: $binlog_f2 + --echo # First binlog in SHOW BINLOG FILES: $binlog_f2_show + --die Wrong order of binary log files in SHOW BINARY LOGS +} ---echo Case: Stop position after EOF, WARNING must appear ---echo # MYSQL_BINLOG --short-form --start-position=4 --stop-position=99 mysql-test/std_data/master-bin.000001 --result-file=warn_pos_test_file.out 2>&1 ---exec $MYSQL_BINLOG --short-form --start-position=4 --stop-position=99 $data_file --result-file=$assert_file 2>&1 +--echo # Ensuring file offset of binlog_f2_mid < binlog_f1_end +if ($binlog_f2_mid > $binlog_f1_end) +{ + --echo # Binlog 1 end: $binlog_f1:$binlog_f1_end + --echo # Binlog 2 stop point: $binlog_f2:$binlog_f2_mid + --die Mid point chosen to end in binlog 2 does not exist in earlier binlog +} ---remove_file $assert_file +#--echo # +#--echo # +#--echo # Test using --read-from-remote-server +#--echo # +#--let $read_from_remote_server= 1 +#--emit warning is not supported by --read-from-remote-server now +#--source binlog_mysqlbinlog_warn_stop_position.inc +--echo # +--echo # +--echo # Test using local binlog files +--echo # +--let $read_from_remote_server= 0 +--source binlog_mysqlbinlog_warn_stop_position.inc + +--echo # --echo # End of binlog_mysqlbinlog_warn_stop_position.test From 04408fff40447f9aab12aed1957356e65e1c8b15 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sun, 12 Jan 2025 13:20:56 +1100 Subject: [PATCH 06/41] MDEV-35687 Various UBSAN function-type-mismatch debug_sync and myisam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit storage/maria/ma_open.c:352:7: runtime error: call to function debug_sync(THD*, char const*, unsigned long) through pointer to incorrect function type 'void (*)(void *, const char *, unsigned long)' The THD argument is a void *. Because of the way myisam is .c files the function prototype is mismatched. As Marko pointed out the MYSQL_THD is declared as void * in C. Thanks Jimmy Hú for noting that struct THD is the equalivalant in C to the class THD. The C NULL was also different to the C++ nullptr. Corrected the definations of MYSQL_THD and DEBUG_SYNC_C to be C and C++ compatible. --- include/mysql/plugin.h | 3 ++- include/mysql/service_debug_sync.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index d9aef6ac11c..87efbefde68 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -44,7 +44,8 @@ class THD; class Item; #define MYSQL_THD THD* #else -#define MYSQL_THD void* +struct THD; +typedef struct THD* MYSQL_THD; #endif typedef char my_bool; diff --git a/include/mysql/service_debug_sync.h b/include/mysql/service_debug_sync.h index 0bd49a13458..f7fdbf04832 100644 --- a/include/mysql/service_debug_sync.h +++ b/include/mysql/service_debug_sync.h @@ -351,7 +351,11 @@ extern void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t); #endif /* defined(ENABLED_DEBUG_SYNC) */ /* compatibility macro */ +#ifdef __cplusplus +#define DEBUG_SYNC_C(name) DEBUG_SYNC(nullptr, name) +#else #define DEBUG_SYNC_C(name) DEBUG_SYNC(NULL, name) +#endif #ifdef __cplusplus } From f862fe8b2bb359e0bbeb48d0d38047a95dc0e43c Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 16 Dec 2024 10:26:21 +1100 Subject: [PATCH 07/41] MDEV-35641 bring call to use_all_columns() forward when reading from mysql.servers TABLE::use_all_columns turn on all bits of read_set, which is interpreted by innodb as a request to read all columns. Without doing so before calling init_read_record(), innodb will not retrieve any columns if mysql.servers table has been altered to use innodb as the engine, and any foreign servers stored in the table are "lost". --- mysql-test/main/servers.result | 7 +++++++ mysql-test/main/servers.test | 9 +++++++++ sql/sql_servers.cc | 6 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/servers.result b/mysql-test/main/servers.result index d660aff1bd2..a02c3d6ac74 100644 --- a/mysql-test/main/servers.result +++ b/mysql-test/main/servers.result @@ -43,3 +43,10 @@ ERROR HY000: Can't read record in system table drop table mysql.servers; rename table mysql.servers_save to mysql.servers; drop server s1; +# +# MDEV-35641 foreign server "disappears" after ALTERing the servers system table to use innodb and FLUSH PRIVILEGES +# +CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (HOST '127.0.0.1'); +ALTER TABLE mysql.servers ENGINE=innodb; +FLUSH PRIVILEGES; +drop server s1; diff --git a/mysql-test/main/servers.test b/mysql-test/main/servers.test index 1a58d5849f8..f46041bb21c 100644 --- a/mysql-test/main/servers.test +++ b/mysql-test/main/servers.test @@ -41,3 +41,12 @@ create server s2 foreign data wrapper foo options(user 'a'); drop table mysql.servers; rename table mysql.servers_save to mysql.servers; drop server s1; + +--echo # +--echo # MDEV-35641 foreign server "disappears" after ALTERing the servers system table to use innodb and FLUSH PRIVILEGES +--echo # +--source include/have_innodb.inc +CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (HOST '127.0.0.1'); +ALTER TABLE mysql.servers ENGINE=innodb; +FLUSH PRIVILEGES; +drop server s1; diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 59a4679847b..ecf411ab313 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -283,7 +283,7 @@ end: static bool servers_load(THD *thd, TABLE_LIST *tables) { - TABLE *table; + TABLE *table= tables[0].table; READ_RECORD read_record_info; bool return_val= TRUE; DBUG_ENTER("servers_load"); @@ -292,7 +292,8 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) free_root(&mem, MYF(0)); init_sql_alloc(key_memory_servers, &mem, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); - if (init_read_record(&read_record_info,thd,table=tables[0].table, NULL, NULL, + table->use_all_columns(); + if (init_read_record(&read_record_info,thd,table, NULL, NULL, 1,0, FALSE)) DBUG_RETURN(1); while (!(read_record_info.read_record())) @@ -405,7 +406,6 @@ get_server_from_table_to_cache(TABLE *table) FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER)); DBUG_ENTER("get_server_from_table_to_cache"); - table->use_all_columns(); /* get each field into the server struct ptr */ ptr= get_field(&mem, table->field[0]); From 0d35fe6e5761cbee731ffcac55f2bf8eaf2a6a8f Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 23 Dec 2024 22:36:01 +0100 Subject: [PATCH 08/41] MDEV-35326: Memory Leak in init_io_cache_ext upon SHUTDOWN The problems were that: 1) resources was freed "asimetric" normal execution in send_eof, in case of error in destructor. 2) destructor was not called in case of SP for result objects. (so if the last SP execution ended with error resorces was not freeded on reinit before execution (cleanup() called before next execution) and destructor also was not called due to lack of delete call for the object) Result cleanup() renamed to reset_for_next_ps_execution() to better reflect function(). All result method revised and freeing resources made "symetric". Destructor of result object called for SP. Added skipped invalidation in case of error in insert. Removed misleading naming of reset(thd) (could be mixed with with reset()). --- sql/item_subselect.cc | 6 +- sql/sp_head.cc | 11 ++++ sql/sp_head.h | 11 +--- sql/sql_class.cc | 56 +++++++++++-------- sql/sql_class.h | 48 ++++++++-------- sql/sql_delete.cc | 14 +++++ sql/sql_insert.cc | 24 +++++++- sql/sql_prepare.cc | 2 +- sql/sql_union.cc | 10 ++-- sql/sql_update.cc | 14 +++++ .../spider/bugfix/r/mdev_35326.result | 14 +++++ .../spider/bugfix/t/mdev_35326.test | 21 +++++++ 12 files changed, 162 insertions(+), 69 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_35326.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_35326.test diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c0ac4022cd9..8da808ca3a0 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3753,7 +3753,7 @@ void subselect_single_select_engine::cleanup() DBUG_ENTER("subselect_single_select_engine::cleanup"); prepared= executed= 0; join= 0; - result->cleanup(); + result->reset_for_next_ps_execution(); select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; DBUG_VOID_RETURN; } @@ -3763,7 +3763,7 @@ void subselect_union_engine::cleanup() { DBUG_ENTER("subselect_union_engine::cleanup"); unit->reinit_exec_mechanism(); - result->cleanup(); + result->reset_for_next_ps_execution(); unit->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) sl->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; @@ -5436,7 +5436,7 @@ void subselect_hash_sj_engine::cleanup() } DBUG_ASSERT(lookup_engine->engine_type() == UNIQUESUBQUERY_ENGINE); lookup_engine->cleanup(); - result->cleanup(); /* Resets the temp table as well. */ + result->reset_for_next_ps_execution(); /* Resets the temp table as well. */ DBUG_ASSERT(tmp_table); free_tmp_table(thd, tmp_table); tmp_table= NULL; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 506e755c2fd..c751636fbf7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3665,6 +3665,17 @@ int sp_lex_keeper::cursor_reset_lex_and_exec_core(THD *thd, uint *nextp, return res; } +sp_lex_keeper::~sp_lex_keeper() +{ + if (m_lex_resp) + { + /* Prevent endless recursion. */ + m_lex->sphead= NULL; + delete m_lex->result; + lex_end(m_lex); + delete m_lex; + } +} /* sp_instr class functions diff --git a/sql/sp_head.h b/sql/sp_head.h index 3de8e843753..ba677053e87 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1273,16 +1273,7 @@ public: { lex->sp_lex_in_use= TRUE; } - virtual ~sp_lex_keeper() - { - if (m_lex_resp) - { - /* Prevent endless recursion. */ - m_lex->sphead= NULL; - lex_end(m_lex); - delete m_lex; - } - } + virtual ~sp_lex_keeper(); /** Prepare execution of instruction using LEX, if requested check whenever diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 73e182edd0f..8cb5b4954aa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3066,7 +3066,7 @@ void Item_change_list::rollback_item_tree_changes() ** Functions to provide a interface to select results *****************************************************************************/ -void select_result::cleanup() +void select_result::reset_for_next_ps_execution() { /* do nothing */ } @@ -3135,6 +3135,7 @@ void select_send::abort_result_set() */ thd->spcont->end_partial_result_set= TRUE; } + reset_for_next_ps_execution(); DBUG_VOID_RETURN; } @@ -3145,7 +3146,7 @@ void select_send::abort_result_set() stored procedure statement. */ -void select_send::cleanup() +void select_send::reset_for_next_ps_execution() { is_result_set_started= FALSE; } @@ -3183,7 +3184,7 @@ bool select_send::send_eof() if (unlikely(thd->is_error())) return TRUE; ::my_eof(thd); - is_result_set_started= 0; + reset_for_next_ps_execution(); return FALSE; } @@ -3192,10 +3193,22 @@ bool select_send::send_eof() Handling writing to file ************************************************************************/ +bool select_to_file::free_recources() +{ + if (file >= 0) + { + (void) end_io_cache(&cache); + bool error= mysql_file_close(file, MYF(MY_WME)); + file= -1; + return error; + } + return FALSE; +} + bool select_to_file::send_eof() { - int error= MY_TEST(end_io_cache(&cache)); - if (unlikely(mysql_file_close(file, MYF(MY_WME))) || + int error= false; + if (unlikely(free_recources()) || unlikely(thd->is_error())) error= true; @@ -3203,20 +3216,19 @@ bool select_to_file::send_eof() { ::my_ok(thd,row_count); } - file= -1; return error; } +void select_to_file::abort_result_set() +{ + select_result_interceptor::abort_result_set(); + free_recources(); +} -void select_to_file::cleanup() +void select_to_file::reset_for_next_ps_execution() { /* In case of error send_eof() may be not called: close the file here. */ - if (file >= 0) - { - (void) end_io_cache(&cache); - mysql_file_close(file, MYF(0)); - file= -1; - } + free_recources(); path[0]= '\0'; row_count= 0; } @@ -3224,12 +3236,8 @@ void select_to_file::cleanup() select_to_file::~select_to_file() { - if (file >= 0) - { // This only happens in case of error - (void) end_io_cache(&cache); - mysql_file_close(file, MYF(0)); - file= -1; - } + DBUG_ASSERT(file < 0); + free_recources(); // just in case } /*************************************************************************** @@ -3716,9 +3724,9 @@ int select_singlerow_subselect::send_data(List &items) } -void select_max_min_finder_subselect::cleanup() +void select_max_min_finder_subselect::reset_for_next_ps_execution() { - DBUG_ENTER("select_max_min_finder_subselect::cleanup"); + DBUG_ENTER("select_max_min_finder_subselect::reset_for_next_ps_execution"); cache= 0; DBUG_VOID_RETURN; } @@ -3943,7 +3951,7 @@ bool select_dumpvar::check_simple_select() const } -void select_dumpvar::cleanup() +void select_dumpvar::reset_for_next_ps_execution() { row_count= 0; } @@ -4372,10 +4380,10 @@ void select_materialize_with_stats::reset() } -void select_materialize_with_stats::cleanup() +void select_materialize_with_stats::reset_for_next_ps_execution() { reset(); - select_unit::cleanup(); + select_unit::reset_for_next_ps_execution(); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 28aef92c31e..032d0bc2606 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5585,7 +5585,8 @@ public: */ virtual int send_data(List &items)=0; virtual ~select_result_sink() = default; - void reset(THD *thd_arg) { thd= thd_arg; } + // Used in cursors to initialize and reset + void reinit(THD *thd_arg) { thd= thd_arg; } }; class select_result_interceptor; @@ -5659,15 +5660,11 @@ public: */ virtual bool check_simple_select() const; virtual void abort_result_set() {} - /* - Cleanup instance of this class for next execution of a prepared - statement/stored procedure. - */ - virtual void cleanup(); + virtual void reset_for_next_ps_execution(); void set_thd(THD *thd_arg) { thd= thd_arg; } - void reset(THD *thd_arg) + void reinit(THD *thd_arg) { - select_result_sink::reset(thd_arg); + select_result_sink::reinit(thd_arg); unit= NULL; } #ifdef EMBEDDED_LIBRARY @@ -5773,9 +5770,9 @@ public: elsewhere. (this is used by ANALYZE $stmt feature). */ void disable_my_ok_calls() { suppress_my_ok= true; } - void reset(THD *thd_arg) + void reinit(THD *thd_arg) { - select_result::reset(thd_arg); + select_result::reinit(thd_arg); suppress_my_ok= false; } protected: @@ -5827,7 +5824,7 @@ private: {} void reset(THD *thd_arg) { - select_result_interceptor::reset(thd_arg); + select_result_interceptor::reinit(thd_arg); spvar_list= NULL; field_count= 0; } @@ -5871,7 +5868,7 @@ public: void reset(THD *thd_arg, sp_lex_keeper *lex_keeper) { sp_cursor_statistics::reset(); - result.reset(thd_arg); + result.reinit(thd_arg); m_lex_keeper= lex_keeper; server_side_cursor= NULL; } @@ -5899,7 +5896,7 @@ public: bool send_eof() override; bool check_simple_select() const override { return FALSE; } void abort_result_set() override; - void cleanup() override; + void reset_for_next_ps_execution() override; select_result_interceptor *result_interceptor() override { return NULL; } }; @@ -5934,7 +5931,9 @@ public: { path[0]=0; } ~select_to_file(); bool send_eof() override; - void cleanup() override; + void abort_result_set() override; + void reset_for_next_ps_execution() override; + bool free_recources(); }; @@ -6011,7 +6010,7 @@ class select_insert :public select_result_interceptor { bool send_eof() override; void abort_result_set() override; /* not implemented: select_insert is never re-used in prepared statements */ - void cleanup() override; + void reset_for_next_ps_execution() override; }; @@ -6231,7 +6230,7 @@ public: int delete_record(); bool send_eof() override; virtual bool flush(); - void cleanup() override; + void reset_for_next_ps_execution() override; virtual bool create_result_table(THD *thd, List *column_types, bool is_distinct, ulonglong options, const LEX_CSTRING *alias, @@ -6406,9 +6405,10 @@ class select_union_recursive :public select_unit */ List rec_table_refs; /* - The count of how many times cleanup() was called with cleaned==false - for the unit specifying the recursive CTE for which this object was created - or for the unit specifying a CTE that mutually recursive with this CTE. + The count of how many times reset_for_next_ps_execution() was called with + cleaned==false for the unit specifying the recursive CTE for which this + object was created or for the unit specifying a CTE that mutually + recursive with this CTE. */ uint cleanup_count; long row_counter; @@ -6427,7 +6427,7 @@ class select_union_recursive :public select_unit bool create_table, bool keep_row_order, uint hidden) override; - void cleanup() override; + void reset_for_next_ps_execution() override; }; /** @@ -6497,7 +6497,7 @@ public: { result->abort_result_set(); /* purecov: inspected */ } - void cleanup() override + void reset_for_next_ps_execution() override { send_records= 0; } @@ -6600,7 +6600,7 @@ public: uint hidden) override; bool init_result_table(ulonglong select_options); int send_data(List &items) override; - void cleanup() override; + void reset_for_next_ps_execution() override; ha_rows get_null_count_of_col(uint idx) { DBUG_ASSERT(idx < table->s->fields); @@ -6633,7 +6633,7 @@ public: bool mx, bool all): select_subselect(thd_arg, item_arg), cache(0), fmax(mx), is_all(all) {} - void cleanup() override; + void reset_for_next_ps_execution() override; int send_data(List &items) override; bool cmp_real(); bool cmp_int(); @@ -7049,7 +7049,7 @@ public: int send_data(List &items) override; bool send_eof() override; bool check_simple_select() const override; - void cleanup() override; + void reset_for_next_ps_execution() override; }; /* Bits in sql_command_flags */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 25b3aef3ebe..fa677feb551 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1422,6 +1422,13 @@ void multi_delete::abort_result_set() { DBUG_ENTER("multi_delete::abort_result_set"); + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + multi_delete::send_eof(). + + ***************************************************************************/ + /* the error was handled or nothing deleted and no side effects return */ if (error_handled || (!thd->transaction->stmt.modified_non_trans_table && !deleted)) @@ -1622,6 +1629,13 @@ bool multi_delete::send_eof() /* reset used flags */ THD_STAGE_INFO(thd, stage_end); + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + multi_delete::abort_result_set(). + + ***************************************************************************/ + if (thd->transaction->stmt.modified_non_trans_table) thd->transaction->all.modified_non_trans_table= TRUE; thd->transaction->all.m_unsafe_rollback_flags|= diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e1d87e29869..000695c5399 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4131,7 +4131,7 @@ int select_insert::prepare2(JOIN *) } -void select_insert::cleanup() +void select_insert::reset_for_next_ps_execution() { /* select_insert/select_create are never re-used in prepared statement */ DBUG_ASSERT(0); @@ -4245,6 +4245,13 @@ bool select_insert::prepare_eof() DBUG_PRINT("enter", ("trans_table: %d, table_type: '%s'", trans_table, table->file->table_type())); + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + select_insert::abort_result_set(). + + ****************************************************************************/ + #ifdef WITH_WSREP error= (thd->wsrep_cs().current_error()) ? -1 : (thd->locked_tables_mode <= LTM_LOCK_TABLES) ? @@ -4377,6 +4384,12 @@ void select_insert::abort_result_set() */ if (table && table->file->is_open()) { + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + select_insert::prepare_eof(). + + ****************************************************************************/ bool changed, transactional_table; /* If we are not in prelocked mode, we end the bulk insert started @@ -4404,7 +4417,14 @@ void select_insert::abort_result_set() If table creation failed, the number of rows modified will also be zero, so no check for that is made. */ - changed= (info.copied || info.deleted || info.updated); + if ((changed= (info.copied || info.deleted || info.updated))) + { + /* + We must invalidate the table in the query cache before binlog writing + and ha_autocommit_or_rollback. + */ + query_cache_invalidate3(thd, table, 1); + } transactional_table= table->file->has_transactions_and_rollback(); if (thd->transaction->stmt.modified_non_trans_table || thd->log_current_statement) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 93e81b2025d..9d53d7cf543 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3194,7 +3194,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) if (lex->result) { - lex->result->cleanup(); + lex->result->reset_for_next_ps_execution(); lex->result->set_thd(thd); } lex->allow_sum_func.clear_all(); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 53e604bfa92..09dc045b543 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -547,7 +547,7 @@ int select_unit::delete_record() tables of JOIN - exec_tmp_table_[1 | 2]. */ -void select_unit::cleanup() +void select_unit::reset_for_next_ps_execution() { table->file->extra(HA_EXTRA_RESET_STATE); table->file->ha_delete_all_rows(); @@ -902,11 +902,11 @@ bool select_unit_ext::send_eof() return (MY_TEST(error)); } -void select_union_recursive::cleanup() +void select_union_recursive::reset_for_next_ps_execution() { if (table) { - select_unit::cleanup(); + select_unit::reset_for_next_ps_execution(); free_tmp_table(thd, table); } @@ -2194,7 +2194,7 @@ bool st_select_lex_unit::exec() if (uncacheable || !item || !item->assigned() || describe) { if (!fake_select_lex && !(with_element && with_element->is_recursive)) - union_result->cleanup(); + union_result->reset_for_next_ps_execution(); for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { ha_rows records_at_start= 0; @@ -2636,7 +2636,7 @@ bool st_select_lex_unit::cleanup() { if (union_result) { - ((select_union_recursive *) union_result)->cleanup(); + ((select_union_recursive *) union_result)->reset_for_next_ps_execution(); delete union_result; union_result= 0; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4a13d83d52f..9dfb681b119 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -2743,6 +2743,13 @@ void multi_update::abort_result_set() (!thd->transaction->stmt.modified_non_trans_table && !updated))) return; + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + multi_update::send_eof(). + + ***************************************************************************/ + /* Something already updated so we have to invalidate cache */ if (updated) query_cache_invalidate3(thd, update_tables, 1); @@ -3072,6 +3079,13 @@ bool multi_update::send_eof() killed_status= (local_error == 0) ? NOT_KILLED : thd->killed; THD_STAGE_INFO(thd, stage_end); + /**************************************************************************** + + NOTE: if you change here be aware that almost the same code is in + multi_update::abort_result_set(). + + ***************************************************************************/ + /* We must invalidate the query cache before binlog writing and ha_autocommit_... */ diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_35326.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_35326.result new file mode 100644 index 00000000000..41481447a6c --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_35326.result @@ -0,0 +1,14 @@ +for master_1 +for child2 +for child3 +CREATE TABLE t (c INT) ENGINE=Spider; +CREATE PROCEDURE p() CONTAINS SQL READS SQL DATA SELECT * FROM t INTO OUTFILE 'foo.txt'; +Warnings: +Warning 1287 ' INTO FROM...' instead +CALL p(); +ERROR HY000: Unable to connect to foreign data source: localhost +drop procedure p; +drop table t; +for master_1 +for child2 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_35326.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_35326.test new file mode 100644 index 00000000000..1ce8e1aa780 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_35326.test @@ -0,0 +1,21 @@ +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +let $MYSQLD_DATADIR= `select @@datadir`; + +CREATE TABLE t (c INT) ENGINE=Spider; +CREATE PROCEDURE p() CONTAINS SQL READS SQL DATA SELECT * FROM t INTO OUTFILE 'foo.txt'; +--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE +CALL p(); +remove_file $MYSQLD_DATADIR/test/foo.txt; +drop procedure p; +drop table t; + +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log From 14f42e12a42e5c5e787b101b2c4600e44ac90cab Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 13 Jan 2025 16:29:11 +0400 Subject: [PATCH 09/41] MDEV-35596 Assertion `type_handler()->result_type() == value.type_handler()->result_type()' failed in virtual bool Item_param::get_date(THD*, MYSQL_TIME*, date_mode_t) This is a cleanup for MDEV-25593. When binding from NULL, IGNORE or DEFAULT, value.type_handler should be set to &type_handler_null, to satisfy the DBUG_ASSERT in Item_param::get_date(). --- sql/item.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sql/item.cc b/sql/item.cc index dd9a9063e55..44bd4bbfbba 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4168,6 +4168,7 @@ void Item_param::set_null() max_length= 0; decimals= 0; state= NULL_VALUE; + value.set_handler(&type_handler_null); DBUG_VOID_RETURN; } @@ -4981,7 +4982,10 @@ void Item_param::set_default(bool set_type_handler_null) */ null_value= true; if (set_type_handler_null) + { + value.set_handler(&type_handler_null); set_handler(&type_handler_null); + } } void Item_param::set_ignore(bool set_type_handler_null) @@ -4990,7 +4994,10 @@ void Item_param::set_ignore(bool set_type_handler_null) state= IGNORE_VALUE; null_value= true; if (set_type_handler_null) + { + value.set_handler(&type_handler_null); set_handler(&type_handler_null); + } } /** From 1327f40f9649f399fec14d1dff0f2bbc55da749a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 13 Jan 2025 17:51:51 +0400 Subject: [PATCH 10/41] MDEV-35596 Assertion `type_handler()->result_type() == value.type_handler()->result_type()' failed in virtual bool Item_param::get_date(THD*, MYSQL_TIME*, date_mode_t) Adding mtr tests forgotten in the previous commit. --- mysql-test/main/ps_11bugs.result | 35 ++++++++++++++++++++++++++++++++ mysql-test/main/ps_11bugs.test | 34 +++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/mysql-test/main/ps_11bugs.result b/mysql-test/main/ps_11bugs.result index 87a3487141b..985654eb283 100644 --- a/mysql-test/main/ps_11bugs.result +++ b/mysql-test/main/ps_11bugs.result @@ -245,4 +245,39 @@ NULL DEALLOCATE PREPARE stmt; SET timestamp=DEFAULT; SET time_zone=DEFAULT; +# +# MDEV-35596 Assertion `type_handler()->result_type() == value.type_handler()->result_type()' failed in virtual bool Item_param::get_date(THD*, MYSQL_TIME*, date_mode_t) +# +CREATE TABLE t (c TIMESTAMP); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +INSERT INTO t (c) VALUES (now()); +EXECUTE s USING NULL; +DROP TABLE t; +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +Warnings: +Warning 1292 Truncated incorrect datetime value: '1' +EXECUTE s USING NULL; +DROP TABLE t; +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +Warnings: +Warning 1292 Truncated incorrect datetime value: '1' +EXECUTE s USING DEFAULT; +ERROR HY000: Default/ignore value is not supported for such parameter usage +DROP TABLE t; +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +Warnings: +Warning 1292 Truncated incorrect datetime value: '1' +EXECUTE s USING IGNORE; +ERROR HY000: Default/ignore value is not supported for such parameter usage +DROP TABLE t; # End of 10.5 tests diff --git a/mysql-test/main/ps_11bugs.test b/mysql-test/main/ps_11bugs.test index 7a0843e9352..7cb5708d062 100644 --- a/mysql-test/main/ps_11bugs.test +++ b/mysql-test/main/ps_11bugs.test @@ -254,4 +254,38 @@ DEALLOCATE PREPARE stmt; SET timestamp=DEFAULT; SET time_zone=DEFAULT; +--echo # +--echo # MDEV-35596 Assertion `type_handler()->result_type() == value.type_handler()->result_type()' failed in virtual bool Item_param::get_date(THD*, MYSQL_TIME*, date_mode_t) +--echo # + +CREATE TABLE t (c TIMESTAMP); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +INSERT INTO t (c) VALUES (now()); +EXECUTE s USING NULL; +DROP TABLE t; + +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +EXECUTE s USING NULL; +DROP TABLE t; + +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +--error ER_INVALID_DEFAULT_PARAM +EXECUTE s USING DEFAULT; +DROP TABLE t; + +CREATE TABLE t (c TIMESTAMP); +INSERT INTO t (c) VALUES ('2001-01-01 10:20:30'); +PREPARE s FROM 'DELETE FROM t WHERE c=?'; +EXECUTE s USING 1; +--error ER_INVALID_DEFAULT_PARAM +EXECUTE s USING IGNORE; +DROP TABLE t; + --echo # End of 10.5 tests From fe2f2377688cdf4862baff753f04f390aec17793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 13 Jan 2025 17:43:58 +0200 Subject: [PATCH 11/41] MDEV-35808 Test case to handle undo tablespace truncation in Mariabackup This is the test case from commit 46aaf328ce424aededdb61e59a48db05630563d5 (MDEV-35830) to cover backup_undo_trunc() in the regression tests of earlier major versions of mariadb-backup. --- .../mariabackup/undo_truncate.combinations | 4 ++ .../suite/mariabackup/undo_truncate.opt | 6 ++ .../suite/mariabackup/undo_truncate.result | 39 ++++++++++++ .../suite/mariabackup/undo_truncate.test | 59 +++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 mysql-test/suite/mariabackup/undo_truncate.combinations create mode 100644 mysql-test/suite/mariabackup/undo_truncate.opt create mode 100644 mysql-test/suite/mariabackup/undo_truncate.result create mode 100644 mysql-test/suite/mariabackup/undo_truncate.test diff --git a/mysql-test/suite/mariabackup/undo_truncate.combinations b/mysql-test/suite/mariabackup/undo_truncate.combinations new file mode 100644 index 00000000000..fe6a3ba58fd --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_truncate.combinations @@ -0,0 +1,4 @@ +[clear] +--innodb-encrypt-log=OFF +[crypt] +--innodb-encrypt-log=ON diff --git a/mysql-test/suite/mariabackup/undo_truncate.opt b/mysql-test/suite/mariabackup/undo_truncate.opt new file mode 100644 index 00000000000..9b4f76ab5de --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_truncate.opt @@ -0,0 +1,6 @@ +--innodb-undo-tablespaces=2 +--plugin-load-add=$FILE_KEY_MANAGEMENT_SO +--loose-file-key-management +--loose-file-key-management-filekey=FILE:$MTR_SUITE_DIR/filekeys-data.key +--loose-file-key-management-filename=$MTR_SUITE_DIR/filekeys-data.enc +--loose-file-key-management-encryption-algorithm=aes_cbc diff --git a/mysql-test/suite/mariabackup/undo_truncate.result b/mysql-test/suite/mariabackup/undo_truncate.result new file mode 100644 index 00000000000..a3bfb182dd8 --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_truncate.result @@ -0,0 +1,39 @@ +SET GLOBAL innodb_undo_log_truncate = 0; +create table t1 (keyc int primary key default 0, c char(6)) engine=innodb; +create table t2 (keyc int primary key default 0, c char(6)) engine=innodb; +CREATE PROCEDURE p(t VARCHAR(64)) +BEGIN +DECLARE i TEXT DEFAULT 'insert into t1 select seq,repeat(chr(48),6) + from seq_1_to_20000'; +DECLARE u1 TEXT DEFAULT 'update t1 set c=repeat(chr(32),6)'; +DECLARE u2 TEXT DEFAULT 'update t1 set c=repeat(chr(64),6)'; +EXECUTE IMMEDIATE REPLACE(i,'t1', t); +EXECUTE IMMEDIATE REPLACE(u1,'t1', t); +EXECUTE IMMEDIATE REPLACE(u2,'t1', t); +END; +$$ +connect con1,localhost,root,,; +begin; +call p('t1'); +connection default; +call p('t2'); +connection con1; +commit; +disconnect con1; +connection default; +DROP PROCEDURE p; +SET GLOBAL innodb_undo_log_truncate = 1; +SET GLOBAL innodb_max_undo_log_size=DEFAULT; +SET GLOBAL innodb_max_purge_lag_wait=0; +# Prepare full backup +# shutdown server +# remove datadir +# xtrabackup move back +# restart +select count(*) from t1; +count(*) +20000 +select count(*) from t2; +count(*) +20000 +DROP TABLE t1,t2; diff --git a/mysql-test/suite/mariabackup/undo_truncate.test b/mysql-test/suite/mariabackup/undo_truncate.test new file mode 100644 index 00000000000..a23c9cf64ff --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_truncate.test @@ -0,0 +1,59 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc +--source include/have_sequence.inc +--source include/have_file_key_management.inc + +SET GLOBAL innodb_undo_log_truncate = 0; + +# +# Perform DML action using multiple clients and multiple undo tablespace. +# + +create table t1 (keyc int primary key default 0, c char(6)) engine=innodb; +create table t2 (keyc int primary key default 0, c char(6)) engine=innodb; + +DELIMITER $$; +CREATE PROCEDURE p(t VARCHAR(64)) +BEGIN + DECLARE i TEXT DEFAULT 'insert into t1 select seq,repeat(chr(48),6) + from seq_1_to_20000'; + DECLARE u1 TEXT DEFAULT 'update t1 set c=repeat(chr(32),6)'; + DECLARE u2 TEXT DEFAULT 'update t1 set c=repeat(chr(64),6)'; + EXECUTE IMMEDIATE REPLACE(i,'t1', t); + EXECUTE IMMEDIATE REPLACE(u1,'t1', t); + EXECUTE IMMEDIATE REPLACE(u2,'t1', t); +END; +$$ +DELIMITER ;$$ + +connect (con1,localhost,root,,); +begin; +send call p('t1'); + +connection default; +call p('t2'); + +connection con1; +reap; +commit; +disconnect con1; +connection default; +DROP PROCEDURE p; + +SET GLOBAL innodb_undo_log_truncate = 1; +SET GLOBAL innodb_max_undo_log_size=DEFAULT; +SET GLOBAL innodb_max_purge_lag_wait=0; +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; + +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 --target-dir=$targetdir --throttle=1000; +--echo # Prepare full backup +exec $XTRABACKUP --prepare --target-dir=$targetdir; +--enable_result_log + +source include/restart_and_restore.inc; +select count(*) from t1; +select count(*) from t2; +# Cleanup +rmdir $targetdir; +DROP TABLE t1,t2; From 133e26fd7dc454c5b154495ab876c76bbcfd1715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 11 Dec 2024 09:34:18 +0200 Subject: [PATCH 12/41] MDEV-34924 : gtid_slave_pos table neven been deleted on non replica nodes (wsrep_gtid_mode = 1) Problem was caused by MDEV-31413 commit 277968aa where mysql.gtid_slave_pos table was replicated by Galera. However, as not all nodes in Galera cluster are replica nodes, rows were not deleted from table. In this fix this is corrected so that mysql.gtid_slave_pos table is not replicated by Galera. Instead when Galera node receives GTID event and wsrep_gtid_mode=1, this event is stored to mysql.gtid_slave_pos table. Added test case galera_2primary_replica for 2 async primaries replicating to galera cluster. Added test case galera_circular_replication where async primary replicates to galera cluster and one of the galera cluster nodes is master to async replica. Modified test case galera_restart_replica to monitor gtid positions and rows in mysql.gtid_pos_table. --- .../galera_2nodes_as_replica_2primary.cnf | 70 ++++++ .../galera/r/galera_2primary_replica.result | 95 +++++++ .../r/galera_circular_replication.result | 138 +++++++++++ .../galera/r/galera_restart_replica.result | 191 ++++++++------ .../galera/t/galera_2primary_replica.cnf | 22 ++ .../galera/t/galera_2primary_replica.test | 170 +++++++++++++ .../galera/t/galera_circular_replication.cnf | 25 ++ .../galera/t/galera_circular_replication.test | 234 ++++++++++++++++++ .../galera/t/galera_restart_replica.test | 197 ++++++++++----- sql/rpl_gtid.cc | 50 +--- sql/wsrep_applier.cc | 5 + sql/wsrep_schema.cc | 80 +++++- sql/wsrep_schema.h | 14 +- 13 files changed, 1110 insertions(+), 181 deletions(-) create mode 100644 mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf create mode 100644 mysql-test/suite/galera/r/galera_2primary_replica.result create mode 100644 mysql-test/suite/galera/r/galera_circular_replication.result create mode 100644 mysql-test/suite/galera/t/galera_2primary_replica.cnf create mode 100644 mysql-test/suite/galera/t/galera_2primary_replica.test create mode 100644 mysql-test/suite/galera/t/galera_circular_replication.cnf create mode 100644 mysql-test/suite/galera/t/galera_circular_replication.test diff --git a/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf b/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf new file mode 100644 index 00000000000..714caf6ee67 --- /dev/null +++ b/mysql-test/suite/galera/galera_2nodes_as_replica_2primary.cnf @@ -0,0 +1,70 @@ +# +# This .cnf file creates a setup with 2 standard MariaDB servers, followed by a 2-node Galera cluster +# + +# Use default setting for mysqld processes +!include include/default_mysqld.cnf + +[mysqld] +loose-innodb +log-bin=mysqld-bin +log-slave-updates +binlog-format=row +innodb-autoinc-lock-mode=2 +default-storage-engine=innodb +# enforce read-committed characteristics across the cluster +# wsrep-causal-reads=ON +wsrep-sync-wait=15 + +[mysqld.1] +wsrep-on=1 +server-id=1 +#galera_port=@OPT.port +#ist_port=@OPT.port +#sst_port=@OPT.port +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address=gcomm:// +wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;gcache.size=10M' +wsrep_node_address='127.0.0.1:@mysqld.1.#galera_port' +wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port +wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port' + +[mysqld.2] +wsrep-on=1 +server-id=2 +#galera_port=@OPT.port +#ist_port=@OPT.port +#sst_port=@OPT.port +wsrep_provider=@ENV.WSREP_PROVIDER +wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port' +wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;gcache.size=10M' +wsrep_node_address='127.0.0.1:@mysqld.2.#galera_port' +wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port +wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port' + +[mysqld.3] +wsrep-on=OFF +server-id=3 +gtid_domain_id=3 + +[mysqld.4] +wsrep-on=OFF +server-id=4 +gtid_domain_id=4 + + +[sst] +sst-log-archive-dir=@ENV.MYSQLTEST_VARDIR/log + +[ENV] +NODE_MYPORT_1= @mysqld.1.port +NODE_MYSOCK_1= @mysqld.1.socket + +NODE_MYPORT_2= @mysqld.2.port +NODE_MYSOCK_2= @mysqld.2.socket + +NODE_MYPORT_3= @mysqld.3.port +NODE_MYSOCK_3= @mysqld.3.socket + +NODE_MYPORT_4= @mysqld.4.port +NODE_MYSOCK_4= @mysqld.4.socket diff --git a/mysql-test/suite/galera/r/galera_2primary_replica.result b/mysql-test/suite/galera/r/galera_2primary_replica.result new file mode 100644 index 00000000000..8bdbf5be962 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_2primary_replica.result @@ -0,0 +1,95 @@ +connection node_2; +connection node_1; +connect primary1, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connect primary2, 127.0.0.1, root, , test, $NODE_MYPORT_4; +connection primary1; +# Primary1 creating user for replication +create user repl@'%' identified by 'repl'; +grant all on *.* to repl@'%'; +connection primary2; +# Primary2 creating user for replication +create user repl2@'%' identified by 'repl2'; +grant all on *.* to repl2@'%'; +connect replica, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection replica; +connection node_2; +connection replica; +# Galera replica changing master to primary1 +SET @@default_master_connection='stream2'; +# Primary node changing master to primary2 +START ALL SLAVES; +Warnings: +Note 1937 SLAVE 'stream1' started +Note 1937 SLAVE 'stream2' started +connection primary1; +# Primary 1: Creating table and populating it with data +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection primary2; +# Primary 2: Creating table and populating it with data +CREATE TABLE t2 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_1000 FROM t2; +EXPECT_1000 +1000 +connection replica; +# Waiting for data to replicate to node_1 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +SELECT COUNT(*) AS EXPECT_1000 FROM t2; +EXPECT_1000 +1000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +3-3-1003,4-4-1003 3-3-1003,4-4-1003 3-3-1003,4-4-1003 +connection node_2; +# Waiting for data to replicate to node_2 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +SELECT COUNT(*) AS EXPECT_1000 FROM t2; +EXPECT_1000 +1000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +3-3-1003,4-4-1003 3-3-1003,4-4-1003 3-3-1003,4-4-1003 +connection primary1; +drop table t1; +connection primary2; +drop table t2; +# Wait until drop table is replicated on Galera +connection replica; +connection node_2; +connection replica; +STOP ALL SLAVES; +Warnings: +Note 1938 SLAVE 'stream1' stopped +Note 1938 SLAVE 'stream2' stopped +RESET SLAVE ALL; +connection primary1; +RESET MASTER; +connection primary2; +RESET MASTER; +connection node_1; +disconnect primary1; +disconnect primary2; +disconnect replica; +disconnect node_2; +disconnect node_1; +# End of test diff --git a/mysql-test/suite/galera/r/galera_circular_replication.result b/mysql-test/suite/galera/r/galera_circular_replication.result new file mode 100644 index 00000000000..72340977005 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_circular_replication.result @@ -0,0 +1,138 @@ +connection node_2; +connection node_1; +connect replica1, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connect primary2, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connect primary1, 127.0.0.1, root, , test, $NODE_MYPORT_4; +connect replica2, 127.0.0.1, root, , test, $NODE_MYPORT_4; +connection primary1; +# Primary1 node creating user for replication +create user repl@'%' identified by 'repl'; +grant all on *.* to repl@'%'; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; +connection replica1; +connection node_2; +connection primary2; +connection replica1; +# Galera replica changing master to primary1 +START SLAVE; +connection primary2; +# Primary2 creating user for replication +create user repl2@'%' identified by 'repl2'; +grant all on *.* to repl2@'%'; +connection replica2; +# replica2 changing master to primary2 +START SLAVE; +connection primary1; +# Primary1: Creating table and populating it with data +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection replica1; +# Waiting for data to replicate to replica +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +# Writing more data to table +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 +connection node_2; +# Waiting for data to replicate to Galera node_2 +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 +# Writing more data to table +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_3000 FROM t1; +EXPECT_3000 +3000 +connection primary2; +# Waiting for data to replicate to primary2 +SELECT COUNT(*) AS EXPECT_3000 FROM t1; +EXPECT_3000 +3000 +# Writing more data to table +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +EXPECT_4000 +4000 +connection primary1; +# Waiting for data to replicate to primary1 +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +EXPECT_4000 +4000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-4-1004,16-15-3002 0-4-1004,16-15-3002 0-4-1004,16-15-3002 +connection replica1; +# Waiting for data to replicate to replica +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +EXPECT_4000 +4000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-4-1004,16-15-3002 0-4-1004,16-15-3002 0-4-1004,16-15-3002 +connection node_2; +# Waiting for data to replicate to node_2 +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +EXPECT_4000 +4000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-4-1004 0-4-1004,16-15-3002 0-4-1004,16-15-3002 +connection primary2; +# Waiting for data to replicate to node_3 +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +EXPECT_4000 +4000 +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-4-1004 0-4-1004,16-15-3002 0-4-1004,16-15-3002 +connection primary1; +drop table t1; +# Wait until drop table is replicated on Galera +connection replica1; +connection node_2; +connection primary2; +connection replica1; +STOP SLAVE; +RESET SLAVE ALL; +connection replica2; +STOP SLAVE; +RESET SLAVE ALL; +RESET MASTER; +connection node_1; +disconnect primary1; +disconnect replica1; +disconnect primary2; +disconnect replica2; +disconnect node_2; +disconnect node_1; +# End of test diff --git a/mysql-test/suite/galera/r/galera_restart_replica.result b/mysql-test/suite/galera/r/galera_restart_replica.result index 9b7e9fd259f..efc9a83a168 100644 --- a/mysql-test/suite/galera/r/galera_restart_replica.result +++ b/mysql-test/suite/galera/r/galera_restart_replica.result @@ -1,122 +1,169 @@ connection node_2; connection node_1; -connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connect replica, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connect primary, 127.0.0.1, root, , test, $NODE_MYPORT_3; create user repl@'%' identified by 'repl'; grant all on *.* to repl@'%'; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; connection node_1; -connection node_2; -connection node_2; +connection replica; +connection replica; START SLAVE; -connection node_3; -CREATE TABLE t1 (id bigint primary key, msg varchar(100)) engine=innodb; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_2; +connection primary; +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection replica; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-1004 0-3-1004 0-3-1004 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 connection node_1; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_2; -# Verify that graceful shutdown succeeds. +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-1004 0-3-1004 0-3-1004 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection replica; +# Verify that graceful shutdown succeeds in replica. # Force SST connection node_1; -# Waiting until node_2 is not part of cluster anymore -connection node_2; -# Start node_2 again -¤ Wait until node_2 is back on cluster -connection node_2; +# Waiting until replica is not part of cluster anymore +connection replica; +# Start replica again +# Wait until replica is back on cluster SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-1004 0-3-1004 0-3-1004 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 connection node_1; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_3; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_3; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-1004 0-3-1004 0-3-1004 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection primary; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 drop table t1; -connection node_2; +connection replica; connection node_1; -connection node_3; -CREATE TABLE t1 (id bigint primary key, msg varchar(100)) engine=innodb; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_2; +connection primary; +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +connection replica; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-2006 0-3-2006 0-3-2006 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 connection node_1; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; -EXPECT_10000 -10000 -connection node_2; -# Verify that graceful shutdown succeeds. +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-2006 0-3-2006 0-3-2006 +connection replica; +# Verify that graceful shutdown succeeds in replica. # Force SST connection node_1; -# Waiting until node_2 is not part of cluster anymore -connection node_3; -SELECT COUNT(*) AS EXPECT_20000 FROM t1; -EXPECT_20000 -20000 -connection node_2; -# Start node_2 again -¤ Wait until node_2 is back on cluster -connection node_2; +# Waiting until replica is not part of cluster anymore +# Add writes to primary +connection primary; +# Intentionally generate 1k GTID-events +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 +connection replica; +# Start replica again +# Wait until replica is back on cluster SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_20000 FROM t1; -EXPECT_20000 -20000 +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-3006 0-3-3006 0-3-3006 +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 connection node_1; SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; EXPECT_1 1 -SELECT COUNT(*) AS EXPECT_20000 FROM t1; -EXPECT_20000 -20000 -connection node_3; -SELECT COUNT(*) AS EXPECT_20000 FROM t1; -EXPECT_20000 -20000 -connection node_3; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +EXPECT_1 +1 +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +@@gtid_slave_pos @@gtid_binlog_pos @@gtid_current_pos +0-3-3006 0-3-3006 0-3-3006 +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 +connection primary; +SELECT COUNT(*) AS EXPECT_2000 FROM t1; +EXPECT_2000 +2000 drop table t1; -connection node_2; +connection replica; connection node_1; -connection node_2; +connection replica; STOP SLAVE; RESET SLAVE ALL; -connection node_3; +connection primary; RESET MASTER; connection node_1; -disconnect node_3; +disconnect primary; +disconnect replica; disconnect node_2; disconnect node_1; # End of test diff --git a/mysql-test/suite/galera/t/galera_2primary_replica.cnf b/mysql-test/suite/galera/t/galera_2primary_replica.cnf new file mode 100644 index 00000000000..e066866de87 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_2primary_replica.cnf @@ -0,0 +1,22 @@ +!include ../galera_2nodes_as_replica_2primary.cnf + +[mysqld] +wsrep-debug=1 + +[mysqld.1] +server_id=15 +wsrep_gtid_mode=1 +wsrep_gtid_domain_id=16 +gtid_domain_id=11 +gtid_strict_mode=1 +wsrep-slave-threads=4 +slave-parallel-threads=2 + +[mysqld.2] +skip-slave-start=OFF +server_id=15 +wsrep_gtid_mode=1 +wsrep_gtid_domain_id=16 +gtid_domain_id=11 +gtid_strict_mode=1 +wsrep-slave-threads=4 diff --git a/mysql-test/suite/galera/t/galera_2primary_replica.test b/mysql-test/suite/galera/t/galera_2primary_replica.test new file mode 100644 index 00000000000..fb57c6637d0 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_2primary_replica.test @@ -0,0 +1,170 @@ +# +# Test two primary nodes async replication to Galera cluster +# +# primary1 primary2 +# #3 #4 +# | | +# | async replication v +# +-------------------+ +----------------+ +# | | +# v v +# galera replica <------galera replication-------->galera node_2 +# #1 #2 +# +# Test outline +# +# - Create user for async replication and table with rows in both primaries +# - Verify that tables and rows are replicated to all Galera nodes +# - Verify that gtid position is same in all Galera nodes +# +# The galera/galera_2nodes_as_replica_2primary.cnf describes the setup of the nodes +# +--source include/force_restart.inc +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# As node #3 and #4 are not a Galera node, and galera_cluster.inc does not open connetion to it +# we open the connections here +--connect primary1, 127.0.0.1, root, , test, $NODE_MYPORT_3 +--connect primary2, 127.0.0.1, root, , test, $NODE_MYPORT_4 +--connection primary1 +--echo # Primary1 creating user for replication +create user repl@'%' identified by 'repl'; +grant all on *.* to repl@'%'; + +--connection primary2 +--echo # Primary2 creating user for replication +create user repl2@'%' identified by 'repl2'; +grant all on *.* to repl2@'%'; + +--connect replica, 127.0.0.1, root, , test, $NODE_MYPORT_1 + +--let $node_1 = replica +--let $node_2 = node_2 +--source include/auto_increment_offset_save.inc + +--connection replica +--echo # Galera replica changing master to primary1 +--disable_query_log +SET @@default_master_connection='stream1'; +--eval CHANGE MASTER 'stream1' TO master_host='127.0.0.1', master_user='repl', master_password='repl', master_port=$NODE_MYPORT_3, master_use_gtid=slave_pos; +--enable_query_log + +SET @@default_master_connection='stream2'; +--echo # Primary node changing master to primary2 +--disable_query_log +--eval CHANGE MASTER 'stream2' TO master_host='127.0.0.1', master_user='repl2', master_password='repl2', master_port=$NODE_MYPORT_4, master_use_gtid=slave_pos; +--enable_query_log + +START ALL SLAVES; + +--connection primary1 +--echo # Primary 1: Creating table and populating it with data +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +--disable_query_log +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_1000 FROM t1; + +--connection primary2 +--echo # Primary 2: Creating table and populating it with data +CREATE TABLE t2 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t2 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_1000 FROM t2; + +--connection replica +--echo # Waiting for data to replicate to node_1 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--let $wait_condition_on_error_output = SHOW ALL SLAVES STATUS; +--source include/wait_condition_with_debug.inc +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2'; +--let $wait_condition_on_error_output = SHOW ALL SLAVES STATUS; +--source include/wait_condition_with_debug.inc + +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t2; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_1000 FROM t2; + +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; + +--connection node_2 +--echo # Waiting for data to replicate to node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2'; +--source include/wait_condition.inc + +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t2; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_1000 FROM t2; +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +# +# Cleanup +# +--connection primary1 +drop table t1; +--connection primary2 +drop table t2; + +--echo # Wait until drop table is replicated on Galera +--connection replica +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2'; +--source include/wait_condition.inc + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2'; +--source include/wait_condition.inc + +--connection replica +STOP ALL SLAVES; +RESET SLAVE ALL; + +--connection primary1 +RESET MASTER; +--connection primary2 +RESET MASTER; + +--source include/auto_increment_offset_restore.inc + +--connection node_1 +--disconnect primary1 +--disconnect primary2 +--disconnect replica + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/galera_circular_replication.cnf b/mysql-test/suite/galera/t/galera_circular_replication.cnf new file mode 100644 index 00000000000..b1c6320d4df --- /dev/null +++ b/mysql-test/suite/galera/t/galera_circular_replication.cnf @@ -0,0 +1,25 @@ +!include ../galera_3nodes_as_slave.cnf + +[mysqld] +wsrep-debug=1 + +[mysqld.1] +server_id=15 +wsrep_gtid_mode=1 +wsrep_gtid_domain_id=16 +gtid_domain_id=11 +gtid_strict_mode=1 + +[mysqld.2] +server_id=15 +wsrep_gtid_mode=1 +wsrep_gtid_domain_id=16 +gtid_domain_id=11 +gtid_strict_mode=1 + +[mysqld.3] +server_id=15 +wsrep_gtid_mode=1 +wsrep_gtid_domain_id=16 +gtid_domain_id=11 +gtid_strict_mode=1 diff --git a/mysql-test/suite/galera/t/galera_circular_replication.test b/mysql-test/suite/galera/t/galera_circular_replication.test new file mode 100644 index 00000000000..dbe85da4b23 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_circular_replication.test @@ -0,0 +1,234 @@ +# +# Test circular replication where galera cluster is async replica and master +# +# mariadb #4 galera galera +# primary1 +# replica2 +# ---async replication-->replica1 #1 <--galera replication--> node_2 #2 +# ^ ^ +# | | galera replication +# | v +# +<------------------async replication----------------------primary2 (galera) #3 +# +# Test outline: +# +# - Create user for async replication in primary1 +# - Create user for async replication in primary2 +# - Create table and some data in primary1 +# - Verify that table and data is replicated to galera nodes +# - Verify that mysql.gtid_slave_pos has some rows in all Galera nodes +# - Verify that gtid_slave_pos, gtid_binlog_pos and gtid_current_pos are +# same in all Galera nodes and primary1 +# - Verify that writes on Galera nodes are replicated to all nodes +# and to primary1 +# +# The galera/galera_3nodes_as_slave.cnf describes the setup of the nodes +# +--source include/force_restart.inc +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--connect replica1, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connect primary2, 127.0.0.1, root, , test, $NODE_MYPORT_3 + +# As node #4 is not a Galera node, and galera_cluster.inc does not open connetion to it +# because it is both primary and replica we open both connections here +--connect primary1, 127.0.0.1, root, , test, $NODE_MYPORT_4 +--connect replica2, 127.0.0.1, root, , test, $NODE_MYPORT_4 + +--connection primary1 +--echo # Primary1 node creating user for replication +create user repl@'%' identified by 'repl'; +grant all on *.* to repl@'%'; +ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; + +--let $node_1 = replica1 +--let $node_2 = node_2 +--let $node_3 = primary2 +--source include/auto_increment_offset_save.inc + +--connection replica1 +--echo # Galera replica changing master to primary1 +--disable_query_log +--eval CHANGE MASTER TO master_host='127.0.0.1', master_user='repl', master_password='repl', master_port=$NODE_MYPORT_4, master_use_gtid=slave_pos; +--enable_query_log +START SLAVE; + +--connection primary2 +--echo # Primary2 creating user for replication +create user repl2@'%' identified by 'repl2'; +grant all on *.* to repl2@'%'; + +--connection replica2 +--echo # replica2 changing master to primary2 +--disable_query_log +--eval CHANGE MASTER TO master_host='127.0.0.1', master_user='repl2', master_password='repl2', master_port=$NODE_MYPORT_3, master_use_gtid=slave_pos; +--enable_query_log +START SLAVE; + +--connection primary1 +--echo # Primary1: Creating table and populating it with data +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_1000 FROM t1; + +--connection replica1 +--echo # Waiting for data to replicate to replica +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_1000 FROM t1; + +--echo # Writing more data to table +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_2000 FROM t1; + +--connection node_2 +--echo # Waiting for data to replicate to Galera node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--let $wait_condition = SELECT COUNT(*) = 2000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_2000 FROM t1; + +--echo # Writing more data to table +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_3000 FROM t1; + +--connection primary2 +--echo # Waiting for data to replicate to primary2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--let $wait_condition = SELECT COUNT(*) = 3000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_3000 FROM t1; + +--echo # Writing more data to table +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 +--disable_query_log +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} +--enable_query_log + +SELECT COUNT(*) AS EXPECT_4000 FROM t1; + +--connection primary1 +--echo # Waiting for data to replicate to primary1 +--let $wait_condition = SELECT COUNT(*) = 4000 FROM t1; +--let $wait_condition_on_error_output = SHOW SLAVE STATUS; +--source include/wait_condition_with_debug.inc + +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; + +--connection replica1 +--echo # Waiting for data to replicate to replica +--let $wait_condition = SELECT COUNT(*) = 4000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; + +--connection node_2 +--echo # Waiting for data to replicate to node_2 +--let $wait_condition = SELECT COUNT(*) = 4000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; + +--connection primary2 +--echo # Waiting for data to replicate to node_3 +--let $wait_condition = SELECT COUNT(*) = 4000 FROM t1; +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_4000 FROM t1; +SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +# +# Cleanup +# +--connection primary1 +drop table t1; + +--echo # Wait until drop table is replicated on Galera +--connection replica1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--connection primary2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + +--connection replica1 +STOP SLAVE; +RESET SLAVE ALL; + +--connection replica2 +STOP SLAVE; +RESET SLAVE ALL; +RESET MASTER; + +--source include/auto_increment_offset_restore.inc + +--connection node_1 +--disconnect primary1 +--disconnect replica1 +--disconnect primary2 +--disconnect replica2 + +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/galera_restart_replica.test b/mysql-test/suite/galera/t/galera_restart_replica.test index 37cfd9bc0f9..05ab77f2519 100644 --- a/mysql-test/suite/galera/t/galera_restart_replica.test +++ b/mysql-test/suite/galera/t/galera_restart_replica.test @@ -1,77 +1,115 @@ # -# Test Galera as a replica to a MySQL async replication +# Test Galera as a replica to a MariaDB async replication +# +# MariaDB +# primary ---async replication--->galera node_2 (replica)<----galera replication---> galera node1 +# +# Test outline: +# +# - Create user for async replication +# - Create table and some data in primary +# - Verify that table and data is replicated to galera nodes +# - Verify that mysql.gtid_slave_pos has some rows in all Galera nodes +# - Verify that gtid_slave_pos, gtid_binlog_pos and gtid_current_pos are +# same in all Galera nodes +# - Verify that we can shutdown and restart Galera replica (node #2) +# - Verify that gtid_slave_pos, gtid_binlog_pos and gtid_current_pos are +# same in all Galera nodes +# - Verify that mysql.gtid_slave_pos table has limited amount of rows +# - Veruft that ddl works (drop table) +# +# Similar test is done so that new rows are added to table in +# primary while async replica (node #2) is down. # # The galera/galera_2node_slave.cnf describes the setup of the nodes # --source include/force_restart.inc --source include/galera_cluster.inc --source include/have_innodb.inc ---source include/have_sequence.inc + +# In this test we mark node #2 as replica +--connect replica, 127.0.0.1, root, , test, $NODE_MYPORT_2 # As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it -# we open the node_3 connection here ---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 +# we open the primary connection her +--connect primary, 127.0.0.1, root, , test, $NODE_MYPORT_3 create user repl@'%' identified by 'repl'; grant all on *.* to repl@'%'; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; --let $node_1 = node_1 ---let $node_2 = node_2 +--let $node_2 = replica --source include/auto_increment_offset_save.inc ---connection node_2 +--connection replica --disable_query_log --eval CHANGE MASTER TO master_host='127.0.0.1', master_user='repl', master_password='repl', master_port=$NODE_MYPORT_3, master_use_gtid=slave_pos; --enable_query_log START SLAVE; ---connection node_3 +--connection primary +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; -CREATE TABLE t1 (id bigint primary key, msg varchar(100)) engine=innodb; +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 --disable_query_log -INSERT INTO t1 SELECT seq, 'test' from seq_1_to_10000; +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} --enable_query_log -SELECT COUNT(*) AS EXPECT_10000 FROM t1; ---connection node_2 +SELECT COUNT(*) AS EXPECT_1000 FROM t1; + +--connection replica --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 10000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; --source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; --connection node_1 --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 10000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; --source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; ---connection node_2 ---echo # Verify that graceful shutdown succeeds. +--connection replica +--echo # Verify that graceful shutdown succeeds in replica. --source include/shutdown_mysqld.inc --echo # Force SST --remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat --connection node_1 ---echo # Waiting until node_2 is not part of cluster anymore +--echo # Waiting until replica is not part of cluster anymore --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc --let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --source include/wait_condition.inc ---connection node_2 ---echo # Start node_2 again +--connection replica +--echo # Start replica again --source include/start_mysqld.inc ---echo ¤ Wait until node_2 is back on cluster +--echo # Wait until replica is back on cluster --let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --source include/wait_condition.inc --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; @@ -79,24 +117,30 @@ SELECT COUNT(*) AS EXPECT_10000 FROM t1; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc ---connection node_2 +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; --connection node_1 +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; ---connection node_3 -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +--connection primary +SELECT COUNT(*) AS EXPECT_1000 FROM t1; # # Cleanup # ---connection node_3 drop table t1; ---connection node_2 +--connection replica --let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc @@ -108,59 +152,80 @@ drop table t1; # Case 2 : While slave is down add writes to master # ---connection node_3 - -CREATE TABLE t1 (id bigint primary key, msg varchar(100)) engine=innodb; +--connection primary +CREATE TABLE t1 (id bigint auto_increment primary key, msg varchar(100)) engine=innodb; +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 --disable_query_log -INSERT INTO t1 SELECT seq, 'test' from seq_1_to_10000; +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} --enable_query_log -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; ---connection node_2 +--connection replica --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 10000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; --source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; --connection node_1 --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 10000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; --source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; +--source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_10000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; ---connection node_2 ---echo # Verify that graceful shutdown succeeds. +--connection replica +--echo # Verify that graceful shutdown succeeds in replica. --source include/shutdown_mysqld.inc --echo # Force SST --remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat --connection node_1 ---echo # Waiting until node_2 is not part of cluster anymore +--echo # Waiting until replica is not part of cluster anymore --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc --let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --source include/wait_condition.inc -# Add writes to master ---connection node_3 +--echo # Add writes to primary +--connection primary +--echo # Intentionally generate 1k GTID-events +--let $inserts=1000 +--let $count=0 --disable_query_log -INSERT INTO t1 SELECT seq, 'test' from seq_20001_to_30000; +while($count < $inserts) +{ + --eval insert into t1 values (NULL,'test1') + --inc $count +} --enable_query_log -SELECT COUNT(*) AS EXPECT_20000 FROM t1; ---connection node_2 ---echo # Start node_2 again +SELECT COUNT(*) AS EXPECT_2000 FROM t1; + +--connection replica +--echo # Start replica again --source include/start_mysqld.inc ---echo ¤ Wait until node_2 is back on cluster +--echo # Wait until replica is back on cluster --let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --source include/wait_condition.inc --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; @@ -168,28 +233,34 @@ SELECT COUNT(*) AS EXPECT_20000 FROM t1; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc ---connection node_2 ---let $wait_condition = SELECT COUNT(*) = 20000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 2000 FROM t1; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; --source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_20000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_2000 FROM t1; --connection node_1 ---let $wait_condition = SELECT COUNT(*) = 20000 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 2000 FROM t1; +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) < 1000 FROM mysql.gtid_slave_pos; --source include/wait_condition.inc SELECT COUNT(*) > 0 AS EXPECT_1 FROM mysql.gtid_slave_pos; -SELECT COUNT(*) AS EXPECT_20000 FROM t1; +SELECT COUNT(*) < 1000 AS EXPECT_1 FROM mysql.gtid_slave_pos; +SELECT @@gtid_slave_pos,@@gtid_binlog_pos,@@gtid_current_pos; +SELECT COUNT(*) AS EXPECT_2000 FROM t1; ---connection node_3 -SELECT COUNT(*) AS EXPECT_20000 FROM t1; +--connection primary +SELECT COUNT(*) AS EXPECT_2000 FROM t1; # # Cleanup # ---connection node_3 drop table t1; ---connection node_2 +--connection replica --let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc @@ -197,16 +268,18 @@ drop table t1; --let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; --source include/wait_condition.inc ---connection node_2 +--connection replica STOP SLAVE; RESET SLAVE ALL; ---connection node_3 +--connection primary RESET MASTER; ---connection node_1 ---disconnect node_3 - --source include/auto_increment_offset_restore.inc + +--connection node_1 +--disconnect primary +--disconnect replica + --source include/galera_end.inc --echo # End of test diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 93a83426d37..8112a5b911d 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -28,10 +28,6 @@ #include "rpl_rli.h" #include "slave.h" #include "log_event.h" -#ifdef WITH_WSREP -#include "wsrep_mysqld.h" // wsrep_thd_is_local -#include "wsrep_trans_observer.h" // wsrep_start_trx_if_not_started -#endif const LEX_CSTRING rpl_gtid_slave_state_table_name= { STRING_WITH_LEN("gtid_slave_pos") }; @@ -696,23 +692,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, goto end; #ifdef WITH_WSREP - /* - We should replicate local gtid_slave_pos updates to other nodes if - wsrep gtid mode is set. - In applier we should not append them to galera writeset. - */ - if (WSREP_ON_ && wsrep_gtid_mode && wsrep_thd_is_local(thd)) - { - thd->wsrep_ignore_table= false; - table->file->row_logging= 1; // replication requires binary logging - if (thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID) - thd->set_query_id(next_query_id()); - wsrep_start_trx_if_not_started(thd); - } - else - { - thd->wsrep_ignore_table= true; - } + thd->wsrep_ignore_table= true; // Do not replicate mysql.gtid_slave_pos table #endif if (!in_transaction) @@ -749,10 +729,6 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, } end: -#ifdef WITH_WSREP - thd->wsrep_ignore_table= false; -#endif - if (table_opened) { if (err || (err= ha_commit_trans(thd, FALSE))) @@ -764,6 +740,10 @@ end: else thd->release_transactional_locks(); } + +#ifdef WITH_WSREP + thd->wsrep_ignore_table= false; +#endif thd->lex->restore_backup_query_tables_list(&lex_backup); thd->variables.option_bits= thd_saved_option; thd->resume_subsequent_commits(suspended_wfc); @@ -877,25 +857,7 @@ rpl_slave_state::gtid_delete_pending(THD *thd, return; #ifdef WITH_WSREP - /* - We should replicate local gtid_slave_pos updates to other nodes if - wsrep gtid mode is set. - In applier we should not append them to galera writeset. - */ - if (WSREP_ON_ && wsrep_gtid_mode && - wsrep_thd_is_local(thd) && - thd->wsrep_cs().state() != wsrep::client_state::s_none) - { - if (thd->wsrep_trx().active() == false) - { - if (thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID) - thd->set_query_id(next_query_id()); - wsrep_start_transaction(thd, thd->wsrep_next_trx_id()); - } - thd->wsrep_ignore_table= false; - } - else - thd->wsrep_ignore_table= true; + thd->wsrep_ignore_table= true; // No Galera replication for mysql.gtid_pos_table #endif thd_saved_option= thd->variables.option_bits; diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index feb78507bf9..39df306a0e2 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -22,6 +22,7 @@ #include "wsrep_xid.h" #include "wsrep_thd.h" #include "wsrep_trans_observer.h" +#include "wsrep_schema.h" // wsrep_schema #include "slave.h" // opt_log_slave_updates #include "debug_sync.h" @@ -180,6 +181,10 @@ int wsrep_apply_events(THD* thd, { thd->variables.gtid_seq_no= gtid_ev->seq_no; } + + if (wsrep_gtid_mode) + wsrep_schema->store_gtid_event(thd, gtid_ev); + delete ev; } continue; diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index 08e516b2a7a..f29442abac1 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2015-2023 Codership Oy +/* Copyright (C) 2015-2025 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,8 @@ #include "wsrep_storage_service.h" #include "wsrep_thd.h" #include "wsrep_server_state.h" +#include "log_event.h" +#include "sql_class.h" #include #include @@ -165,6 +167,24 @@ private: my_bool m_wsrep_on; }; +class wsrep_ignore_table +{ +public: + wsrep_ignore_table(THD* thd) + : m_thd(thd) + , m_wsrep_ignore_table(thd->wsrep_ignore_table) + { + thd->wsrep_ignore_table= true; + } + ~wsrep_ignore_table() + { + m_thd->wsrep_ignore_table= m_wsrep_ignore_table; + } +private: + THD* m_thd; + my_bool m_wsrep_ignore_table; +}; + class thd_server_status { public: @@ -1535,3 +1555,61 @@ int Wsrep_schema::recover_sr_transactions(THD *orig_thd) out: DBUG_RETURN(ret); } + +int Wsrep_schema::store_gtid_event(THD* thd, + const Gtid_log_event *gtid) +{ + DBUG_ENTER("Wsrep_schema::store_gtid_event"); + int error=0; + void *hton= NULL; + const bool in_transaction= (gtid->flags2 & Gtid_log_event::FL_TRANSACTIONAL); + const bool in_ddl= (gtid->flags2 & Gtid_log_event::FL_DDL); + + DBUG_PRINT("info", ("thd: %p, in_transaction: %d, in_ddl: %d " + "in_active_multi_stmt_transaction: %d", + thd, in_transaction, in_ddl, + thd->in_active_multi_stmt_transaction())); + + Wsrep_schema_impl::wsrep_ignore_table ignore_table(thd); + Wsrep_schema_impl::binlog_off binlog_off(thd); + Wsrep_schema_impl::sql_safe_updates sql_safe_updates(thd); + + rpl_group_info *rgi= thd->wsrep_rgi; + const uint64 sub_id= rpl_global_gtid_slave_state->next_sub_id(gtid->domain_id); + rpl_gtid current_gtid; + current_gtid.domain_id= gtid->domain_id; + current_gtid.server_id= gtid->server_id; + current_gtid.seq_no= gtid->seq_no; + rgi->gtid_pending= false; + + DBUG_ASSERT(!in_transaction || thd->in_active_multi_stmt_transaction()); + + if ((error= rpl_global_gtid_slave_state->record_gtid(thd, ¤t_gtid, + sub_id, + in_transaction, false, &hton))) + goto out; + + rpl_global_gtid_slave_state->update_state_hash(sub_id, ¤t_gtid, hton, rgi); + + if (in_ddl) + { + // Commit transaction if this GTID is part of DDL-clause because + // DDL causes implicit commit assuming there is no multi statement + // transaction ongoing. + if((error= trans_commit_stmt(thd))) + goto out; + + (void)trans_commit(thd); + } + +out: + if (error) + { + WSREP_DEBUG("Wsrep_schema::store_gtid_event %llu-%llu-%llu failed error=%s (%d).", + gtid->domain_id, gtid->server_id, gtid->seq_no, strerror(error), error); + (void)trans_rollback_stmt(thd); + (void)trans_rollback(thd); + } + + DBUG_RETURN(error); +} diff --git a/sql/wsrep_schema.h b/sql/wsrep_schema.h index f0f79046768..46acba2961b 100644 --- a/sql/wsrep_schema.h +++ b/sql/wsrep_schema.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015-2023 Codership Oy +/* Copyright (C) 2015-2024 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +22,6 @@ #include "mysqld.h" #include "wsrep_mysqld.h" - /* Forward decls */ @@ -32,6 +31,7 @@ struct TABLE; struct TABLE_LIST; struct st_mysql_lex_string; typedef struct st_mysql_lex_string LEX_STRING; +class Gtid_log_event; /** Name of the table in `wsrep_schema_str` used for storing streaming replication data. In an InnoDB full format, e.g. "database/tablename". */ @@ -133,6 +133,16 @@ class Wsrep_schema */ int recover_sr_transactions(THD* orig_thd); + /** + Store GTID-event to mysql.gtid_slave_pos table. + + @param thd The THD object of the calling thread. + @param gtid GTID event from binlog. + + @return Zero on success, non-zero on failure. + */ + int store_gtid_event(THD* thd, const Gtid_log_event *gtid); + private: /* Non-copyable */ Wsrep_schema(const Wsrep_schema&); From d8c841d0d4fcd7a37e1e135052838d8fba565c92 Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Mon, 13 Jan 2025 07:04:53 -0700 Subject: [PATCH 13/41] MDEV-35096: History is stored in different partitions on different nodes when using SYSTEM VERSION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Row-injection updates don’t correctly set the historical partition for tables with system versioning and system_time partitions. This results in inconsistencies between the master and slave when replicating transactions that target such tables (i.e. the primary server would correctly distribute archived rows amongst its partitions, whereas the replica would have all archived rows in a single partition). The function partition_info::vers_set_hist_part(THD*) is used to set the partition; however, its initial check for vers_require_hist_part(THD*) returns false, bypassing the rest of the function (which sets up the partition to use). This is because the actual check uses the LEX sql_command (via LEX::vers_history_generating()) to determine if the command is valid to generate history. Row injections don’t have sql_commands though. This patch provides a fix which extends the check in vers_history_generating() to additionally allow row injections to be history generating (via the function LEX::is_stmt_row_injection()). Special thanks to Jan Lindstrom for his work in reproducing the bug, and providing an initial test case. Reviewed By ============ Kristian Nielsen Aleksey Midenkov --- .../r/rpl_system_versioning_partitions.result | 71 +++++ .../t/rpl_system_versioning_partitions.cnf | 4 + .../t/rpl_system_versioning_partitions.test | 248 ++++++++++++++++++ sql/sql_lex.h | 6 +- 4 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/rpl/r/rpl_system_versioning_partitions.result create mode 100644 mysql-test/suite/rpl/t/rpl_system_versioning_partitions.cnf create mode 100644 mysql-test/suite/rpl/t/rpl_system_versioning_partitions.test diff --git a/mysql-test/suite/rpl/r/rpl_system_versioning_partitions.result b/mysql-test/suite/rpl/r/rpl_system_versioning_partitions.result new file mode 100644 index 00000000000..8edc6996a05 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_system_versioning_partitions.result @@ -0,0 +1,71 @@ +include/master-slave.inc +[connection master] +# +# Initialize system-versioned and partitioned table and its data +connection master; +SET timestamp=UNIX_TIMESTAMP('2025-01-01 01:00:00.000000'); +RESET MASTER; +create table t1 (x int) engine=InnoDB with system versioning partition by system_time limit 3 partitions 5; +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +insert into t1 values(4); +insert into t1 values(5); +# Verifying master partitions are correct after data insertion.. +# .. done +connection slave; +connection slave; +# Verifying partitions of master and slave match on data setup.. +# .. done +# +# "Delete" each row -- these are the BINLOG commands generated by +# mysqlbinlog from `delete from t1 where x=` statments. Because the +# table uses system versioning and system_time partition, the actual +# events are updates, with added fields for the `row_start` and `row_end` +# columns. +connection master; +# BINLOG for Format Description event +BINLOG ' +APZ0Zw8BAAAA/AAAAAABAAAAAAQAMTAuNi4yMS1NYXJpYURCLWRlYnVnLWxvZwAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAA9nRnEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA +CgoKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAEEwQADQgICAoKCgHgiCNP +'; +# BINLOG for delete from t1 where x=1; +BINLOG ' +APZ0ZxMBAAAAMQAAAAQHAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBvaHPfA== +APZ0ZxgBAAAASAAAAEwHAAAAACEAAAAAAAEAAwcH+AEAAABndPYAAAAAf////w9CP/gBAAAAZ3T2 +AAAAAGd09gAAAADnhA23 +'; +# BINLOG for delete from t1 where x=2; +BINLOG ' +APZ0ZxMBAAAAMQAAAPUHAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBwNtQNQ== +APZ0ZxgBAAAASAAAAD0IAAAAACEAAAAAAAEAAwcH+AIAAABndPYAAAAAf////w9CP/gCAAAAZ3T2 +AAAAAGd09gAAAABPYZUX +'; +# BINLOG for delete from t1 where x=3; +BINLOG ' +APZ0ZxMBAAAAMQAAAOYIAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBKWGevg== +APZ0ZxgBAAAASAAAAC4JAAAAACEAAAAAAAEAAwcH+AMAAABndPYAAAAAf////w9CP/gDAAAAZ3T2 +AAAAAGd09gAAAAD0hz5S +'; +# BINLOG for delete from t1 where x=4; +BINLOG ' +APZ0ZxMBAAAAMQAAANcJAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBaT9IZg== +APZ0ZxgBAAAASAAAAB8KAAAAACEAAAAAAAEAAwcH+AQAAABndPYAAAAAf////w9CP/gEAAAAZ3T2 +AAAAAGd09gAAAADA4Tdx +'; +# BINLOG for delete from t1 where x=5; +BINLOG ' +APZ0ZxMBAAAAMQAAAMgKAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBMk64Mw== +APZ0ZxgBAAAASAAAABALAAAAACEAAAAAAAEAAwcH+AUAAABndPYAAAAAf////w9CP/gFAAAAZ3T2 +AAAAAGd09gAAAAA5blY6 +'; +# Verifying master partitions are correct after deletion BINLOG stmts.. +# .. done +connection slave; +connection slave; +connection master; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.cnf b/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.cnf new file mode 100644 index 00000000000..53153614f0a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.cnf @@ -0,0 +1,4 @@ +!include ../my.cnf + +[mysqld] +default_time_zone="-7:00" diff --git a/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.test b/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.test new file mode 100644 index 00000000000..70103acf862 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_system_versioning_partitions.test @@ -0,0 +1,248 @@ +# +# Ensure that executing row-injected events (i.e. via BINLOG statments and +# row-based binlog events) uses historical partitions. That is, for tables +# which use system versioning and system_time partitions, MDEV-35096 reported +# that row-injected events would not be stored into the correct historical +# partition. This test considers both use cases of row-injected events. +# +# The test setup creates a system-versioned table with system_time-based +# partitioning and fills the table up with enough records that bypass the size +# limit of each historical partition. +# +# To test BINLOG statements, a series of BINLOG statements are used to delete +# all the records in the test tables, and the resulting partitions are analyzed +# to ensure that they match the partition specification. The BINLOG events +# were collected by running an original set of delete statements on the table +# data, and taking their binlog data from mysqlbinlog. Note these binary log +# events are actually Update events, because system versioning just archives +# the rows, rather than deleting them. +# +# To test row-based event replication, a slave replicates the master's +# events, and the partitions are compared between the slave and master for +# consistency. +# +# Note that the TIMESTAMP of this test is fixed so the BINLOG statements can +# identify the correct rows to delete (system versioning adds implicit fields +# `row_start` and `row_end`, which are automatically populated using the current +# timestamp). +# +# +# References: +# MDEV-35096: History is stored in different partitions on different nodes +# when using SYSTEM VERSION +# +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--source include/have_innodb.inc +--source include/have_partition.inc + +--echo # +--echo # Initialize system-versioned and partitioned table and its data +--connection master + +# Fix the timestamp for the system versioned row_start and row_end fields, so +# the later hard-coded BINLOG base64 data can find the rows. +SET timestamp=UNIX_TIMESTAMP('2025-01-01 01:00:00.000000'); +RESET MASTER; + +create table t1 (x int) engine=InnoDB with system versioning partition by system_time limit 3 partitions 5; +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +insert into t1 values(4); +insert into t1 values(5); +--let $master_total_size= `select count(*) from t1` +--let $master_p0_size= `select count(*) from t1 partition (p0)` +--let $master_p1_size= `select count(*) from t1 partition (p1)` +--let $master_p2_size= `select count(*) from t1 partition (p2)` + +--echo # Verifying master partitions are correct after data insertion.. +if ($master_total_size != 5) +{ + --echo # Master t1 count: $master_total_size + --die Master table t1 should have 5 entries +} +if ($master_p0_size) +{ + --echo # Master t1,p0 count: $master_p0_size + --die Master t1 partition p0 should be empty +} +if ($master_p1_size) +{ + --echo # Master t1,p1 count: $master_p1_size + --die Master t1 partition p1 should be empty +} +if ($master_p2_size) +{ + --echo # Master t1,p2 count: $master_p2_size + --die Master t1 partition p2 should be empty +} +--echo # .. done + +--sync_slave_with_master + +--connection slave +--let $slave_total_size= `select count(*) from t1` +--let $slave_p0_size= `select count(*) from t1 partition (p0)` +--let $slave_p1_size= `select count(*) from t1 partition (p1)` +--let $slave_p2_size= `select count(*) from t1 partition (p2)` + +--echo # Verifying partitions of master and slave match on data setup.. +if ($slave_total_size != $master_total_size) +{ + --connection master + select count(*) from t0; + --connection slave + select count(*) from t1; + --die Size of t1 differs between master and slave +} +if ($slave_p0_size != $master_p0_size) +{ + --connection master + select count(*) from t1 partition (p0); + --connection slave + select count(*) from t1 partition (p0); + --die Size of t1 partition p0 differs between master and slave +} +if ($slave_p1_size != $master_p1_size) +{ + --connection master + select count(*) from t1 partition (p1); + --connection slave + select count(*) from t1 partition (p1); + --die Size of t1 partition p1 differs between master and slave +} +if ($slave_p2_size != $master_p2_size) +{ + --connection master + select count(*) from t1 partition (p2); + --connection slave + select count(*) from t1 partition (p2); + --die Size of t1 partition p2 differs between master and slave +} +--echo # .. done + +--echo # +--echo # "Delete" each row -- these are the BINLOG commands generated by +--echo # mysqlbinlog from `delete from t1 where x=` statments. Because the +--echo # table uses system versioning and system_time partition, the actual +--echo # events are updates, with added fields for the `row_start` and `row_end` +--echo # columns. +--connection master + +--echo # BINLOG for Format Description event +BINLOG ' +APZ0Zw8BAAAA/AAAAAABAAAAAAQAMTAuNi4yMS1NYXJpYURCLWRlYnVnLWxvZwAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAA9nRnEzgNAAgAEgAEBAQEEgAA5AAEGggAAAAICAgCAAAACgoKAAAAAAAA +CgoKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAEEwQADQgICAoKCgHgiCNP +'; + +--echo # BINLOG for delete from t1 where x=1; +BINLOG ' +APZ0ZxMBAAAAMQAAAAQHAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBvaHPfA== +APZ0ZxgBAAAASAAAAEwHAAAAACEAAAAAAAEAAwcH+AEAAABndPYAAAAAf////w9CP/gBAAAAZ3T2 +AAAAAGd09gAAAADnhA23 +'; + +--echo # BINLOG for delete from t1 where x=2; +BINLOG ' +APZ0ZxMBAAAAMQAAAPUHAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBwNtQNQ== +APZ0ZxgBAAAASAAAAD0IAAAAACEAAAAAAAEAAwcH+AIAAABndPYAAAAAf////w9CP/gCAAAAZ3T2 +AAAAAGd09gAAAABPYZUX +'; + + +--echo # BINLOG for delete from t1 where x=3; +BINLOG ' +APZ0ZxMBAAAAMQAAAOYIAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBKWGevg== +APZ0ZxgBAAAASAAAAC4JAAAAACEAAAAAAAEAAwcH+AMAAABndPYAAAAAf////w9CP/gDAAAAZ3T2 +AAAAAGd09gAAAAD0hz5S +'; + +--echo # BINLOG for delete from t1 where x=4; +BINLOG ' +APZ0ZxMBAAAAMQAAANcJAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBaT9IZg== +APZ0ZxgBAAAASAAAAB8KAAAAACEAAAAAAAEAAwcH+AQAAABndPYAAAAAf////w9CP/gEAAAAZ3T2 +AAAAAGd09gAAAADA4Tdx +'; + +--echo # BINLOG for delete from t1 where x=5; +BINLOG ' +APZ0ZxMBAAAAMQAAAMgKAAAAACEAAAAAAAEABHRlc3QAAnQxAAMDERECBgYBMk64Mw== +APZ0ZxgBAAAASAAAABALAAAAACEAAAAAAAEAAwcH+AUAAABndPYAAAAAf////w9CP/gFAAAAZ3T2 +AAAAAGd09gAAAAA5blY6 +'; + +--let $master_total_size= `select count(*) from t1` +--let $master_p0_size= `select count(*) from t1 partition (p0)` +--let $master_p1_size= `select count(*) from t1 partition (p1)` +--let $master_p2_size= `select count(*) from t1 partition (p2)` +--echo # Verifying master partitions are correct after deletion BINLOG stmts.. +if ($master_total_size > 0) +{ + --echo # Master t1 count: $master_total_size + --die Master table t1 should have 0 count +} +if ($master_p0_size != 3) +{ + --echo # Master t1,p0 count: $master_p0_size + --die Master t1 partition p0 should have 3 entries +} +if ($master_p1_size != 2) +{ + --echo # Master t1,p1 count: $master_p1_size + --die Master t1 partition p1 should have 2 entries +} +if ($master_p2_size) +{ + --echo # Master t1,p2 count: $master_p2_size + --die Master t1 partition p2 should be empty +} +--echo # .. done +--sync_slave_with_master + +--connection slave +--let $slave_total_size= `select count(*) from t1` +--let $slave_p0_size= `select count(*) from t1 partition (p0)` +--let $slave_p1_size= `select count(*) from t1 partition (p1)` +--let $slave_p2_size= `select count(*) from t1 partition (p2)` + +if ($slave_total_size != $master_total_size) +{ + --connection master + select count(*) from t1; + --connection slave + select count(*) from t1; + --die Size of t1 differs between master and slave +} +if ($slave_p0_size != $master_p0_size) +{ + --connection master + select count(*) from t1 partition (p0); + --connection slave + select count(*) from t1 partition (p0); + --die Size of t1 partition p0 differs between master and slave +} +if ($slave_p1_size != $master_p1_size) +{ + --connection master + select count(*) from t1 partition (p1); + --connection slave + select count(*) from t1 partition (p1); + --die Size of t1 partition p1 differs between master and slave +} +if ($slave_p2_size != $master_p2_size) +{ + --connection master + select count(*) from t1 partition (p2); + --connection slave + select count(*) from t1 partition (p2); + --die Size of t1 partition p2 differs between master and slave +} + +--connection master +drop table t1; + +--source include/rpl_end.inc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 1dbd839ac53..f1c3e041c7a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -4617,7 +4617,11 @@ public: case SQLCOM_LOAD: return duplicates == DUP_REPLACE; default: - return false; + /* + Row injections (i.e. row binlog events and BINLOG statements) should + generate history. + */ + return is_stmt_row_injection(); } } From 4b0ac5a12b95afbb47a7c41b33b3e8785c9f21a4 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 14 Jan 2025 10:48:59 +1100 Subject: [PATCH 14/41] MDEV-35838 libressl support differences in CRYPTO_set_mem_functions Based on FreeBSD patch. The FreeBSD inclusion of check_openssl_compatibility prevented any use of the crypto callbacks and as such the later differences where ignored. The later differences in coc_malloc didn't propegate to the other callback functions of CRYPTO_set_mem_functions where a reduced argument list also applied. Looking where[2] libressl added the functions it was of the same prototype 10 years ago so omitting any version check. [1] https://github.com/freebsd/freebsd-ports/blob/a34cf9c2dbf503c8248371ba3bab24f34d2d045d/databases/mariadb106-server/files/patch-mysys__ssl_openssl.c [2] https://github.com/libressl/openbsd/commit/5ebad8aceae77c6da6a1e47c3f7e70e8ffae3dae#diff-7f393e5489e6c5780773408f11ca27d9b3bb8f55b174631a1e9467a1dd3010b9R22 --- mysys_ssl/openssl.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c index e0271817309..3890e3524be 100644 --- a/mysys_ssl/openssl.c +++ b/mysys_ssl/openssl.c @@ -36,8 +36,12 @@ int check_openssl_compatibility() static uint testing; static size_t alloc_size, alloc_count; -static void *coc_malloc(size_t size, const char *f __attribute__((unused)), - int l __attribute__((unused))) +static void *coc_malloc(size_t size +#ifndef LIBRESSL_VERSION_NUMBER + , const char *f __attribute__((unused)), + int l __attribute__((unused)) +#endif +) { if (unlikely(testing)) { @@ -47,15 +51,22 @@ static void *coc_malloc(size_t size, const char *f __attribute__((unused)), return malloc(size); } -static void *coc_realloc(void *addr, size_t num, - const char *file __attribute__((unused)), - int line __attribute__((unused))) +static void *coc_realloc(void *addr, size_t num +#ifndef LIBRESSL_VERSION_NUMBER + , const char *file __attribute__((unused)), + int line __attribute__((unused)) +#endif +) { return realloc(addr, num); } -static void coc_free(void *addr, const char *file __attribute__((unused)), - int line __attribute__((unused))) +static void coc_free(void *addr +#ifndef LIBRESSL_VERSION_NUMBER + , const char *file __attribute__((unused)), + int line __attribute__((unused)) +#endif +) { free(addr); } From 901c6c7ab63f9c9473b90d3f62be656321bcf871 Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Mon, 25 Dec 2023 13:59:07 +0300 Subject: [PATCH 15/41] MDEV-33064: Sync trx->wsrep state from THD on trx start InnoDB transactions may be reused after committed: - when taken from the transaction pool - during a DDL operation execution In this case wsrep flag on trx object is cleared, which may cause wrong execution logic afterwards (wsrep-related hooks are not run). Make trx->wsrep flag initialize from THD object only once on InnoDB transaction start and don't change it throughout the transaction's lifetime. The flag is reset at commit time as before. Unconditionally set wsrep=OFF for THD objects that represent InnoDB background threads. Make Wsrep_schema::store_view() operate in its own transaction. Fix streaming replication transactions' fragments rollback to not switch THD->wsrep value during transaction's execution (use THD->wsrep_ignore_table as a workaround). Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/r/MDEV-33064.result | 26 ++++++++++ mysql-test/suite/galera/t/MDEV-33064.test | 57 +++++++++++++++++++++ sql/handler.cc | 4 +- sql/sql_class.cc | 6 ++- sql/wsrep_schema.cc | 23 ++++++++- sql/wsrep_server_service.cc | 24 +-------- storage/innobase/handler/ha_innodb.cc | 11 ++-- storage/innobase/trx/trx0trx.cc | 3 ++ 8 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-33064.result create mode 100644 mysql-test/suite/galera/t/MDEV-33064.test diff --git a/mysql-test/suite/galera/r/MDEV-33064.result b/mysql-test/suite/galera/r/MDEV-33064.result new file mode 100644 index 00000000000..22e1ce7a77a --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-33064.result @@ -0,0 +1,26 @@ +connection node_2; +connection node_1; +connect con1,127.0.0.1,root,,test,$NODE_MYPORT_1; +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1_fk(c1 INT PRIMARY KEY, c2 INT, INDEX (c2), FOREIGN KEY (c2) REFERENCES t1(c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +connection con1; +SET SESSION wsrep_retry_autocommit = 0; +SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL may_alter WAIT_FOR bf_abort'; +INSERT INTO t1_fk VALUES (1, 1); +connection node_1; +SET DEBUG_SYNC = 'now WAIT_FOR may_alter'; +SET DEBUG_SYNC = 'lock_wait_end WAIT_FOR alter_continue'; +ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=INPLACE; +connection con1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +SET DEBUG_SYNC = 'now SIGNAL alter_continue'; +connection node_1; +connection node_2; +INSERT INTO t1 (c1, c2) VALUES (2, 2); +connection node_1; +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1_fk, t1; +disconnect con1; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/MDEV-33064.test b/mysql-test/suite/galera/t/MDEV-33064.test new file mode 100644 index 00000000000..704ed70ab56 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-33064.test @@ -0,0 +1,57 @@ +# +# MDEV-33064: ALTER INPLACE running TOI should abort a conflicting DML operation +# +# DDL operations may commit InnoDB transactions more than once during the execution. +# In this case wsrep flag on trx object is cleared, which may cause wrong logic of +# such operations afterwards (wsrep-related hooks are not run). +# One of the consequences was that DDL operation couldn't abort a DML operation +# holding conflicting locks. +# +# The fix: re-enable wsrep flag on trx restart if it's a part of a DDL operation. +# + +--source include/galera_cluster.inc +--source include/have_debug_sync.inc +--source include/have_debug.inc + +--connect con1,127.0.0.1,root,,test,$NODE_MYPORT_1 + +CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1_fk(c1 INT PRIMARY KEY, c2 INT, INDEX (c2), FOREIGN KEY (c2) REFERENCES t1(c1)) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1); + +--connection con1 +SET SESSION wsrep_retry_autocommit = 0; +SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL may_alter WAIT_FOR bf_abort'; +# INSERT also grabs FK-referenced table lock. +--send + INSERT INTO t1_fk VALUES (1, 1); + +--connection node_1 +SET DEBUG_SYNC = 'now WAIT_FOR may_alter'; +SET DEBUG_SYNC = 'lock_wait_end WAIT_FOR alter_continue'; +# ALTER BF-aborts INSERT. +--send + ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=INPLACE; + +--connection con1 +# INSERT gets BF-aborted. +--error ER_LOCK_DEADLOCK +--reap +SET DEBUG_SYNC = 'now SIGNAL alter_continue'; + +--connection node_1 +# ALTER succeeds. +--reap + +--connection node_2 +# Sanity check that ALTER has been replicated. +INSERT INTO t1 (c1, c2) VALUES (2, 2); + +# Cleanup. +--connection node_1 +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1_fk, t1; +--disconnect con1 +--source include/galera_end.inc diff --git a/sql/handler.cc b/sql/handler.cc index 4ecd1ea2048..38453b5e2a7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7500,7 +7500,9 @@ int handler::ha_delete_row(const uchar *buf) } #ifdef WITH_WSREP THD *thd= ha_thd(); - if (WSREP_NNULL(thd)) + /* For streaming replication, when removing fragments, don't call + wsrep_after_row() as that would initiate new streaming transaction */ + if (WSREP_NNULL(thd) && !thd->wsrep_ignore_table) { /* for streaming replication, the following wsrep_after_row() may replicate a fragment, so we have to declare potential PA diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8cb5b4954aa..66f689c5312 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5083,6 +5083,9 @@ MYSQL_THD create_background_thd() thd->real_id= 0; thd->thread_id= 0; thd->query_id= 0; +#ifdef WITH_WSREP + thd->variables.wsrep_on= FALSE; +#endif /* WITH_WSREP */ return thd; } @@ -6347,7 +6350,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) wsrep_is_active(this) && variables.wsrep_trx_fragment_size > 0) { - if (!is_current_stmt_binlog_format_row()) + if (!is_current_stmt_binlog_disabled() && + !is_current_stmt_binlog_format_row()) { my_message(ER_NOT_SUPPORTED_YET, "Streaming replication not supported with " diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index f29442abac1..8e271565b13 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -768,6 +768,12 @@ int Wsrep_schema::store_view(THD* thd, const Wsrep_view& view) Wsrep_schema_impl::binlog_off binlog_off(thd); Wsrep_schema_impl::sql_safe_updates sql_safe_updates(thd); + if (trans_begin(thd, MYSQL_START_TRANS_OPT_READ_WRITE)) + { + WSREP_ERROR("Failed to start transaction for store view"); + goto out_not_started; + } + /* Clean up cluster table and members table. */ @@ -861,7 +867,22 @@ int Wsrep_schema::store_view(THD* thd, const Wsrep_view& view) #endif /* WSREP_SCHEMA_MEMBERS_HISTORY */ ret= 0; out: + if (ret) + { + trans_rollback_stmt(thd); + if (!trans_rollback(thd)) + { + close_thread_tables(thd); + } + } + else if (trans_commit(thd)) + { + ret= 1; + WSREP_ERROR("Failed to commit transaction for store view"); + } + thd->release_transactional_locks(); +out_not_started: DBUG_RETURN(ret); } @@ -1213,7 +1234,7 @@ int Wsrep_schema::remove_fragments(THD* thd, int ret= 0; WSREP_DEBUG("Removing %zu fragments", fragments.size()); - Wsrep_schema_impl::wsrep_off wsrep_off(thd); + Wsrep_schema_impl::wsrep_ignore_table wsrep_ignore_table(thd); Wsrep_schema_impl::binlog_off binlog_off(thd); Wsrep_schema_impl::sql_safe_updates sql_safe_updates(thd); diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc index a2879b59789..b50a3081660 100644 --- a/sql/wsrep_server_service.cc +++ b/sql/wsrep_server_service.cc @@ -241,29 +241,9 @@ void Wsrep_server_service::log_view( view.state_id().seqno().get() >= prev_view.state_id().seqno().get()); } - if (trans_begin(applier->m_thd, MYSQL_START_TRANS_OPT_READ_WRITE)) + if (wsrep_schema->store_view(applier->m_thd, view)) { - WSREP_WARN("Failed to start transaction for store view"); - } - else - { - if (wsrep_schema->store_view(applier->m_thd, view)) - { - WSREP_WARN("Failed to store view"); - trans_rollback_stmt(applier->m_thd); - if (!trans_rollback(applier->m_thd)) - { - close_thread_tables(applier->m_thd); - } - } - else - { - if (trans_commit(applier->m_thd)) - { - WSREP_WARN("Failed to commit transaction for store view"); - } - } - applier->m_thd->release_transactional_locks(); + WSREP_WARN("Failed to store view"); } /* diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c2341aa667a..68e3f6c7b56 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2381,9 +2381,6 @@ innobase_trx_init( trx->check_unique_secondary = !thd_test_options( thd, OPTION_RELAXED_UNIQUE_CHECKS); -#ifdef WITH_WSREP - trx->wsrep = wsrep_on(thd); -#endif DBUG_VOID_RETURN; } @@ -4173,9 +4170,6 @@ innobase_commit_low( trx_commit_for_mysql(trx); } else { trx->will_lock = false; -#ifdef WITH_WSREP - trx->wsrep = false; -#endif /* WITH_WSREP */ } #ifdef WITH_WSREP @@ -8571,7 +8565,10 @@ func_exit: } #ifdef WITH_WSREP - if (error == DB_SUCCESS && trx->is_wsrep() + if (error == DB_SUCCESS && + /* For sequences, InnoDB transaction may not have been started yet. + Check THD-level wsrep state in that case. */ + (trx->is_wsrep() || (!trx_is_started(trx) && wsrep_on(m_user_thd))) && wsrep_thd_is_local(m_user_thd) && !wsrep_thd_ignore_table(m_user_thd) && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE) diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 284437497b5..38393444932 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -953,6 +953,7 @@ trx_start_low( #ifdef WITH_WSREP trx->xid->null(); + trx->wsrep = wsrep_on(trx->mysql_thd); #endif /* WITH_WSREP */ ut_a(ib_vector_is_empty(trx->autoinc_locks)); @@ -1402,6 +1403,8 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) trx_finalize_for_fts(this, undo_no != 0); #ifdef WITH_WSREP + ut_ad(is_wsrep() == wsrep_on(mysql_thd)); + /* Serialization history has been written and the transaction is committed in memory, which makes this commit ordered. Release commit order critical section. */ From d1f2ceee1bb1d33e181b5f35b12ed8536a8a0d24 Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Thu, 20 Jun 2024 12:34:55 +0300 Subject: [PATCH 16/41] MDEV-33064: Sync trx->wsrep state from THD on trx start Replace trx->wsrep= 0 with an assert in trx_rollback_for_mysql() Signed-off-by: Julius Goryavsky --- storage/innobase/trx/trx0roll.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index fbe5a7e9b0a..626dd7378f6 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -211,7 +211,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) trx->will_lock = false; ut_ad(trx->mysql_thd); #ifdef WITH_WSREP - trx->wsrep= false; + ut_ad(!trx->is_wsrep()); trx->lock.was_chosen_as_wsrep_victim= false; #endif return(DB_SUCCESS); From 6868d965db1e14f2441c3bff05f0156079524c35 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 14 Jan 2025 08:54:14 +1100 Subject: [PATCH 17/41] MDEV-34825 FreeBSD fails to build under clang natively (postfix) The fix in MDEV-34825/#3484/dff354e7df2f originally just took the FreeBSD carried patch of inline ASM as it didn't have the __ppc_get_timebase function. What clang does have is the __builtin_ppc_get_timebase, which was replaced in the same commit, which was the fix taken from Alpine. To reduce complexity - we only need one working function rather than an equivalent asm implementation. Noted by Marko, thanks! --- include/my_cpu.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/my_cpu.h b/include/my_cpu.h index 1f562dc700c..f9b0c5f0c6d 100644 --- a/include/my_cpu.h +++ b/include/my_cpu.h @@ -94,13 +94,8 @@ static inline void MY_RELAX_CPU(void) __asm__ __volatile__ ("pause"); #endif #elif defined(_ARCH_PWR8) -#ifdef __FreeBSD__ - uint64_t __tb; - __asm__ volatile ("mfspr %0, 268" : "=r" (__tb)); -#else - /* Changed from __ppc_get_timebase for musl compatibility */ + /* Changed from __ppc_get_timebase for musl and clang compatibility */ __builtin_ppc_get_timebase(); -#endif #elif defined __GNUC__ && (defined __arm__ || defined __aarch64__) /* Mainly, prevent the compiler from optimizing away delay loops */ #ifdef _aarch64_ From 200c235244bd06d12fc4d01c79830f2e8b2512cf Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Thu, 9 Jan 2025 17:54:57 -0700 Subject: [PATCH 18/41] MDEV-35429 my_snprintf fixes for 10.5+ * Innobase `os0file.cc`: use `PRIu64` over `llu` * These came after I prepared #3485. * MyISAM `mi_check.c`: in impossible block length warning * I missed this one in #3485 (and #3360 too?). --- storage/innobase/os/os0file.cc | 6 +++--- storage/myisam/mi_check.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 012f23b3b8d..c6106d47557 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -1641,8 +1641,8 @@ bool os_file_set_size(const char *name, os_file_t file, os_offset_t size, if (is_sparse) { bool success = !ftruncate(file, size); if (!success) { - sql_print_error("InnoDB: ftruncate of file %s" - " to %llu bytes failed with error %d", + sql_print_error("InnoDB: ftruncate of file %s to %" + PRIu64 " bytes failed with error %d", name, size, errno); } return success; @@ -1680,7 +1680,7 @@ bool os_file_set_size(const char *name, os_file_t file, os_offset_t size, case 0: return true; default: - sql_print_error("InnoDB: preallocating %llu" + sql_print_error("InnoDB: preallocating %" PRIu64 " bytes for file %s failed with error %d", size, name, err); /* fall through */ diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index e46dc35f861..dff5fcdbcb6 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -3429,9 +3429,9 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param) { if (!searching) mi_check_print_info(param, - "Found block with impossible length %u at %s; Skipped", - block_info.block_len+ (uint) (block_info.filepos-pos), - llstr(pos,llbuff)); + "Found block with impossible length %lu at %s; Skipped", + block_info.block_len + (unsigned long) (block_info.filepos-pos), + llstr(pos, llbuff)); if (found_record) goto try_next; searching=1; From b337e14440ba4fa79a5b4fd34341e6bce4eecbc7 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 19/41] WITHOUT_ABI_CHECK ABI check takes several seconds on compilation. It is not needed in repetitive build during the development process. --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 642f7b39b99..2c1e2719e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -501,7 +501,9 @@ IF(UNIX) ADD_SUBDIRECTORY(man) ENDIF() -INCLUDE(cmake/abi_check.cmake) +IF (NOT WITHOUT_ABI_CHECK) + INCLUDE(cmake/abi_check.cmake) +ENDIF() INCLUDE(cmake/tags.cmake) INCLUDE(for_clients) ADD_SUBDIRECTORY(scripts) From 52dd4895157da932d152d8d762df0989613ffb9d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 20/41] MDEV-22441 implement a generic way to change a value of a variable in a scope Example: { auto _= make_scope_value(var, tmp_value); } make_scope_value(): a function which returns RAII object which temporary changes a value of a variable detail::Scope_value: actual implementation of such RAII class. It shouldn't be used directly! That's why it's inside a namespace detail. --- include/scope.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ sql/sql_acl.cc | 6 ++++-- sql/sql_show.cc | 4 ++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/include/scope.h b/include/scope.h index e0e9fc62969..836c4f77b35 100644 --- a/include/scope.h +++ b/include/scope.h @@ -72,3 +72,48 @@ make_scope_exit(Callable &&f) #define ANONYMOUS_VARIABLE CONCAT(_anonymous_variable, __LINE__) #define SCOPE_EXIT auto ANONYMOUS_VARIABLE= make_scope_exit + +namespace detail +{ + +template class Scope_value +{ +public: + Scope_value(T &variable, const T &scope_value) + : variable_(variable), saved_value_(variable) + { + variable= scope_value; + } + + Scope_value(Scope_value &&rhs) + : variable_(rhs.variable_), saved_value_(rhs.saved_value_), + engaged_(rhs.engaged_) + { + rhs.engaged_= false; + } + + Scope_value(const Scope_value &)= delete; + Scope_value &operator=(const Scope_value &)= delete; + Scope_value &operator=(Scope_value &&)= delete; + + ~Scope_value() + { + if (engaged_) + variable_= saved_value_; + } + +private: + T &variable_; + T saved_value_; + bool engaged_= true; +}; + +} // namespace detail + +// Use like this: +// auto _= make_scope_value(var, tmp_value); +template +detail::Scope_value make_scope_value(T &variable, const T &scope_value) +{ + return detail::Scope_value(variable, scope_value); +} diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 59980264741..98e79babcc3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -54,6 +54,7 @@ #include "sql_array.h" #include "sql_hset.h" #include "password.h" +#include "scope.h" #include "sql_plugin_compat.h" #include "wsrep_mysqld.h" @@ -2552,10 +2553,11 @@ static bool acl_load(THD *thd, const Grant_tables& tables) { READ_RECORD read_record_info; char tmp_name[SAFE_NAME_LEN+1]; - Sql_mode_save old_mode_save(thd); DBUG_ENTER("acl_load"); - thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + auto _= make_scope_value(thd->variables.sql_mode, + thd->variables.sql_mode & + ~MODE_PAD_CHAR_TO_FULL_LENGTH); grant_version++; /* Privileges updated */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2965cdf0199..ee3d85e6ba2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -65,6 +65,7 @@ #include "transaction.h" #include "opt_trace.h" #include "my_cpu.h" +#include "scope.h" #include "lex_symbol.h" @@ -6437,8 +6438,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, { Field *field; LEX_CSTRING tmp_string; - Sql_mode_save sql_mode_backup(thd); - thd->variables.sql_mode= sql_mode; + auto _= make_scope_value(thd->variables.sql_mode, sql_mode); if (sph->type() == SP_TYPE_FUNCTION) { From d8adc5286373f366c74c56a53cbb4258e9b315d3 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 21/41] MDEV-22441 SCOPE_VALUE macro for temporary values - Needless engaged_ removed; - SCOPE_VALUE, SCOPE_SET, SCOPE_CLEAR macros for neater declaration; - IF_CLASS / IF_NOT_CLASS SFINAE checkers to pass arg by value or reference; - inline keyword; - couple of refactorings of temporary free_list. --- include/scope.h | 83 ++++++++++++++++++++++++++++++++++++---------- sql/sql_acl.cc | 4 +-- sql/sql_prepare.cc | 21 +++++------- sql/sql_show.cc | 2 +- 4 files changed, 76 insertions(+), 34 deletions(-) diff --git a/include/scope.h b/include/scope.h index 836c4f77b35..932ab410d78 100644 --- a/include/scope.h +++ b/include/scope.h @@ -32,6 +32,11 @@ public: { } + template + scope_exit(F &&f, bool engaged) : function_(std::forward(f)), engaged_(engaged) + { + } + scope_exit(scope_exit &&rhs) : function_(std::move(rhs.function_)), engaged_(rhs.engaged_) { @@ -43,6 +48,7 @@ public: scope_exit &operator=(const scope_exit &)= delete; void release() { engaged_= false; } + void engage() { DBUG_ASSERT(!engaged_); engaged_= true; } ~scope_exit() { @@ -58,38 +64,51 @@ private: } // end namespace detail template -detail::scope_exit::type> -make_scope_exit(Callable &&f) +inline +::detail::scope_exit::type> +make_scope_exit(Callable &&f, bool engaged= true) { - return detail::scope_exit::type>( - std::forward(f)); + return ::detail::scope_exit::type>( + std::forward(f), engaged); } #define CONCAT_IMPL(x, y) x##y - #define CONCAT(x, y) CONCAT_IMPL(x, y) - #define ANONYMOUS_VARIABLE CONCAT(_anonymous_variable, __LINE__) #define SCOPE_EXIT auto ANONYMOUS_VARIABLE= make_scope_exit +#define IF_CLASS(C) typename std::enable_if::value>::type +#define IF_NOT_CLASS(C) typename std::enable_if::value>::type + namespace detail { -template class Scope_value +template +class Scope_value { public: + // Use SFINAE for passing structs by reference and plain types by value. + // This ctor is defined only if T is a class or struct: + template Scope_value(T &variable, const T &scope_value) - : variable_(variable), saved_value_(variable) + : variable_(&variable), saved_value_(variable) + { + variable= scope_value; + } + + // This ctor is defined only if T is NOT a class or struct: + template + Scope_value(T &variable, const T scope_value) + : variable_(&variable), saved_value_(variable) { variable= scope_value; } Scope_value(Scope_value &&rhs) - : variable_(rhs.variable_), saved_value_(rhs.saved_value_), - engaged_(rhs.engaged_) + : variable_(rhs.variable_), saved_value_(rhs.saved_value_) { - rhs.engaged_= false; + rhs.variable_= NULL; } Scope_value(const Scope_value &)= delete; @@ -98,22 +117,50 @@ public: ~Scope_value() { - if (engaged_) - variable_= saved_value_; + if (variable_) + *variable_= saved_value_; } private: - T &variable_; + T *variable_; T saved_value_; - bool engaged_= true; }; } // namespace detail // Use like this: // auto _= make_scope_value(var, tmp_value); -template -detail::Scope_value make_scope_value(T &variable, const T &scope_value) + +template +inline +::detail::Scope_value make_scope_value(T &variable, const T &scope_value) { - return detail::Scope_value(variable, scope_value); + return ::detail::Scope_value(variable, scope_value); } + +template +inline +::detail::Scope_value make_scope_value(T &variable, T scope_value) +{ + return ::detail::Scope_value(variable, scope_value); +} + +/* + Note: perfect forwarding version can not pass const: + + template + inline + detail::Scope_value make_scope_value(T &variable, U &&scope_value) + { + return detail::Scope_value(variable, std::forward(scope_value)); + } + + as `const U &&` fails with error `expects an rvalue for 2nd argument`. That + happens because const U && is treated as rvalue only (this is the exact syntax + for declaring rvalues). +*/ + + +#define SCOPE_VALUE auto ANONYMOUS_VARIABLE= make_scope_value +#define SCOPE_SET(VAR, MASK) auto ANONYMOUS_VARIABLE= make_scope_value(VAR, VAR | MASK) +#define SCOPE_CLEAR(VAR, MASK) auto ANONYMOUS_VARIABLE= make_scope_value(VAR, VAR & ~MASK) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 98e79babcc3..c7f2a8d3d46 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2555,9 +2555,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) char tmp_name[SAFE_NAME_LEN+1]; DBUG_ENTER("acl_load"); - auto _= make_scope_value(thd->variables.sql_mode, - thd->variables.sql_mode & - ~MODE_PAD_CHAR_TO_FULL_LENGTH); + SCOPE_CLEAR(thd->variables.sql_mode, MODE_PAD_CHAR_TO_FULL_LENGTH); grant_version++; /* Privileges updated */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d53d7cf543..c102e2f734e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2993,8 +2993,8 @@ void mysql_sql_stmt_execute_immediate(THD *thd) DBUG_VOID_RETURN; // out of memory // See comments on thd->free_list in mysql_sql_stmt_execute() - Item *free_list_backup= thd->free_list; - thd->free_list= NULL; + SCOPE_VALUE(thd->free_list, (Item *) NULL); + SCOPE_EXIT([thd]() mutable { thd->free_items(); }); /* Make sure we call Prepared_statement::execute_immediate() with an empty THD::change_list. It can be non empty as the above @@ -3017,8 +3017,6 @@ void mysql_sql_stmt_execute_immediate(THD *thd) Item_change_list_savepoint change_list_savepoint(thd); (void) stmt->execute_immediate(query.str, (uint) query.length); change_list_savepoint.rollback(thd); - thd->free_items(); - thd->free_list= free_list_backup; /* stmt->execute_immediately() sets thd->query_string with the executed @@ -3578,8 +3576,13 @@ void mysql_sql_stmt_execute(THD *thd) so they don't get freed in case of re-prepare. See MDEV-10702 Crash in SET STATEMENT FOR EXECUTE */ - Item *free_list_backup= thd->free_list; - thd->free_list= NULL; // Hide the external (e.g. "SET STATEMENT") Items + /* + Hide and restore at scope exit the "external" (e.g. "SET STATEMENT") Item list. + It will be freed normaly in THD::cleanup_after_query(). + */ + SCOPE_VALUE(thd->free_list, (Item *) NULL); + // Free items created by execute_loop() at scope exit + SCOPE_EXIT([thd]() mutable { thd->free_items(); }); /* Make sure we call Prepared_statement::execute_loop() with an empty THD::change_list. It can be non-empty because the above @@ -3603,12 +3606,6 @@ void mysql_sql_stmt_execute(THD *thd) (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL); change_list_savepoint.rollback(thd); - thd->free_items(); // Free items created by execute_loop() - /* - Now restore the "external" (e.g. "SET STATEMENT") Item list. - It will be freed normaly in THD::cleanup_after_query(). - */ - thd->free_list= free_list_backup; stmt->lex->restore_set_statement_var(); DBUG_VOID_RETURN; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ee3d85e6ba2..dff2a9c73da 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6438,7 +6438,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table, { Field *field; LEX_CSTRING tmp_string; - auto _= make_scope_value(thd->variables.sql_mode, sql_mode); + SCOPE_VALUE(thd->variables.sql_mode, sql_mode); if (sph->type() == SP_TYPE_FUNCTION) { From 92383f8db17b0a3eb95b63c6aee4220017fe63da Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 22/41] MDEV-26891 Segfault in Field::register_field_in_read_map upon INSERT DELAYED with virtual columns Segfault was cause by two different copies of same Field instance in prepared delayed insert. One was made by Delayed_insert::get_local_table() (see make_new_field()). That copy went through parse_vcol_defs() and received new vcol_info->expr. Another one was made by copy_keys_from_share() by this code: /* We are using only a prefix of the column as a key: Create a new field for the key part that matches the index */ field= key_part->field=field->make_new_field(root, outparam, 0); field->field_length= key_part->length; So, key_part and table got different objects of same field and the crash was because key_part->field->vcol_info->expr is NULL. The fix does update_keypart_vcol_info() to update vcol_info->expr in key_part->field. Cleanup: memdup_vcol() is static inline instead of macro + check OOM. --- mysql-test/suite/vcol/r/vcol_misc.result | 14 ++++++++++ mysql-test/suite/vcol/t/vcol_misc.test | 19 ++++++++++++++ sql/sql_insert.cc | 30 +++++++++++++++------ sql/table.cc | 33 ++++++++++++++---------- sql/table.h | 1 + 5 files changed, 75 insertions(+), 22 deletions(-) diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index 64c56e81815..2900cd4b4f4 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -577,3 +577,17 @@ drop table t; # # End of 10.4 tests # +# +# MDEV-26891 Segfault in Field::register_field_in_read_map upon INSERT DELAYED with virtual columns +# +CREATE TABLE t ( +id INT AUTO_INCREMENT, +a varchar(16) NOT NULL DEFAULT '', +b varchar(16) GENERATED ALWAYS AS (a) VIRTUAL, +KEY `col_year` (b(8),id) +) ENGINE=MyISAM; +INSERT DELAYED INTO t (a) VALUES ('foo'),('bar'); +DROP TABLE t; +# +# End of 10.5 tests +# diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 83a06e83f6f..2709ff5b465 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -541,3 +541,22 @@ drop table t; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-26891 Segfault in Field::register_field_in_read_map upon INSERT DELAYED with virtual columns +--echo # +CREATE TABLE t ( + id INT AUTO_INCREMENT, + a varchar(16) NOT NULL DEFAULT '', + b varchar(16) GENERATED ALWAYS AS (a) VIRTUAL, + KEY `col_year` (b(8),id) +) ENGINE=MyISAM; + +INSERT DELAYED INTO t (a) VALUES ('foo'),('bar'); + +# Cleanup +DROP TABLE t; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 000695c5399..50a1a37e3ea 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2674,12 +2674,21 @@ end_create: DBUG_RETURN(thd->is_error()); } -#define memdup_vcol(thd, vcol) \ - if (vcol) \ - { \ - (vcol)= (Virtual_column_info*)(thd)->memdup((vcol), sizeof(*(vcol))); \ - (vcol)->expr= NULL; \ +static inline +bool memdup_vcol(THD *thd, Virtual_column_info *&vcol) +{ + if (vcol) + { + vcol= (Virtual_column_info*)(thd->memdup(vcol, sizeof(*vcol))); + if (!vcol) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return true; + } + vcol->expr= NULL; } + return false; +} /** As we can't let many client threads modify the same TABLE @@ -2820,9 +2829,12 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) (*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0] (*field)->flags|= ((*org_field)->flags & LONG_UNIQUE_HASH_FIELD); (*field)->invisible= (*org_field)->invisible; - memdup_vcol(client_thd, (*field)->vcol_info); - memdup_vcol(client_thd, (*field)->default_value); - memdup_vcol(client_thd, (*field)->check_constraint); + if (memdup_vcol(client_thd, (*field)->vcol_info)) + goto error; + if (memdup_vcol(client_thd, (*field)->default_value)) + goto error; + if (memdup_vcol(client_thd, (*field)->check_constraint)) + goto error; if (*org_field == found_next_number_field) (*field)->table->found_next_number_field= *field; } @@ -2839,6 +2851,8 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) &error_reported, VCOL_INIT_DEPENDENCY_FAILURE_IS_WARNING))) goto error; + + copy->update_keypart_vcol_info(); } switch_defaults_to_nullable_trigger_fields(copy); diff --git a/sql/table.cc b/sql/table.cc index aaec593df76..11564e85af0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3952,6 +3952,24 @@ bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root) return 0; } +void TABLE::update_keypart_vcol_info() +{ + for (uint k= 0; k < s->keys; k++) + { + KEY &info_k= key_info[k]; + uint parts = (s->use_ext_keys ? info_k.ext_key_parts : + info_k.user_defined_key_parts); + for (uint p= 0; p < parts; p++) + { + KEY_PART_INFO &kp= info_k.key_part[p]; + if (kp.field != field[kp.fieldnr - 1]) + { + kp.field->vcol_info = field[kp.fieldnr - 1]->vcol_info; + } + } + } +} + /* Open a table based on a TABLE_SHARE @@ -4184,20 +4202,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, /* Update to use trigger fields */ switch_defaults_to_nullable_trigger_fields(outparam); - for (uint k= 0; k < share->keys; k++) - { - KEY &key_info= outparam->key_info[k]; - uint parts = (share->use_ext_keys ? key_info.ext_key_parts : - key_info.user_defined_key_parts); - for (uint p= 0; p < parts; p++) - { - KEY_PART_INFO &kp= key_info.key_part[p]; - if (kp.field != outparam->field[kp.fieldnr - 1]) - { - kp.field->vcol_info = outparam->field[kp.fieldnr - 1]->vcol_info; - } - } - } + outparam->update_keypart_vcol_info(); } #ifdef WITH_PARTITION_STORAGE_ENGINE diff --git a/sql/table.h b/sql/table.h index b3e23ab02e8..d46f91ee2dd 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1695,6 +1695,7 @@ public: bool is_filled_at_execution(); bool update_const_key_parts(COND *conds); + void update_keypart_vcol_info(); inline void initialize_opt_range_structures(); From 0cf2176b7975abeacc7c1e7c5f673440c26953c6 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 23/41] MDEV-34033 Exchange partition with virtual columns fails MDEV-28127 did is_equal() which compared vcol expressions literally. But another table vcol expression is not equal because of different table name. We implement another comparison method is_identical() which respects different table name in vcol comparison. If any field item points to table_A and compared field item points to table_B, such items are treated as equal in (table_A, table_B) comparison. This is done by cloning table_B expression and renaming any table_B entries to table_A in it. --- mysql-test/main/partition_exchange.result | 22 ++++++++++++++++ mysql-test/main/partition_exchange.test | 32 +++++++++++++++++++++++ sql/field.h | 3 +++ sql/item.cc | 24 +++++++++++++++++ sql/item.h | 9 +++++++ sql/sql_class.h | 1 + sql/sql_partition_admin.cc | 2 ++ sql/sql_table.cc | 6 ++++- sql/table.cc | 21 +++++++++++++++ 9 files changed, 119 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/partition_exchange.result b/mysql-test/main/partition_exchange.result index c82d8d2071b..999517f4028 100644 --- a/mysql-test/main/partition_exchange.result +++ b/mysql-test/main/partition_exchange.result @@ -1321,3 +1321,25 @@ CREATE TABLE t2 (a INT, PRIMARY KEY(a)) CHECKSUM=1, ENGINE=InnoDB; ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2; ERROR HY000: Tables have different definitions DROP TABLE t1, t2; +# +# MDEV-34033 Exchange partition with virtual columns fails +# +create or replace table t1( +id int primary key, +col1 int, +col2 boolean as (col1 is null)) +partition by list (id) ( partition p1 values in (1) +); +create or replace table t1_working like t1; +alter table t1_working remove partitioning; +alter table t1 exchange partition p1 with table t1_working; +create or replace table t2( +id int primary key, +col1 int, +col2 boolean as (true)) +partition by list (id) ( partition p1 values in (1) +); +create or replace table t2_working like t2; +alter table t2_working remove partitioning; +alter table t2 exchange partition p1 with table t2_working; +drop tables t1, t1_working, t2, t2_working; diff --git a/mysql-test/main/partition_exchange.test b/mysql-test/main/partition_exchange.test index 4125e998623..e92b8dfff5c 100644 --- a/mysql-test/main/partition_exchange.test +++ b/mysql-test/main/partition_exchange.test @@ -554,3 +554,35 @@ ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2; # Cleanup DROP TABLE t1, t2; + +--echo # +--echo # MDEV-34033 Exchange partition with virtual columns fails +--echo # +# this fails when the virtual persistent column +# references another column +create or replace table t1( + id int primary key, + col1 int, + col2 boolean as (col1 is null)) + partition by list (id) ( partition p1 values in (1) +); + +create or replace table t1_working like t1; +alter table t1_working remove partitioning; +alter table t1 exchange partition p1 with table t1_working; + +# this works when the virtual persistent column +# does not reference another column +create or replace table t2( + id int primary key, + col1 int, + col2 boolean as (true)) + partition by list (id) ( partition p1 values in (1) +); + +create or replace table t2_working like t2; +alter table t2_working remove partitioning; +alter table t2 exchange partition p1 with table t2_working; + +# Cleanup +drop tables t1, t1_working, t2, t2_working; diff --git a/sql/field.h b/sql/field.h index 7ea431e8acb..3894c22e6da 100644 --- a/sql/field.h +++ b/sql/field.h @@ -659,6 +659,9 @@ public: bool cleanup_session_expr(); bool fix_and_check_expr(THD *thd, TABLE *table); inline bool is_equal(const Virtual_column_info* vcol) const; + /* Same as is_equal() but for comparing with different table */ + bool is_equivalent(THD *thd, TABLE_SHARE *share, TABLE_SHARE *vcol_share, + const Virtual_column_info* vcol, bool &error) const; inline void print(String*); }; diff --git a/sql/item.cc b/sql/item.cc index 44bd4bbfbba..e6e69629fe5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -833,6 +833,30 @@ bool Item_field::rename_fields_processor(void *arg) return 0; } +/** + Rename table and clean field for EXCHANGE comparison +*/ + +bool Item_field::rename_table_processor(void *arg) +{ + Item::func_processor_rename_table *p= (Item::func_processor_rename_table*) arg; + + /* If (db_name, table_name) matches (p->old_db, p->old_table) + rename to (p->new_db, p->new_table) */ + if (((!db_name.str && !p->old_db.str) || + db_name.streq(p->old_db)) && + ((!table_name.str && !p->old_table.str) || + table_name.streq(p->old_table))) + { + db_name= p->new_db; + table_name= p->new_table; + } + + /* Item_field equality is done by field pointer if it is set, we need to avoid that */ + field= NULL; + return 0; +} + /** Check if an Item_field references some field from a list of fields. diff --git a/sql/item.h b/sql/item.h index 147b12dfa8b..a146107508f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2148,6 +2148,7 @@ public: virtual bool check_partition_func_processor(void *arg) { return 1;} virtual bool post_fix_fields_part_expr_processor(void *arg) { return 0; } virtual bool rename_fields_processor(void *arg) { return 0; } + virtual bool rename_table_processor(void *arg) { return 0; } /* TRUE if the function is knowingly TRUE or FALSE. Not to be used for AND/OR formulas. @@ -2176,6 +2177,13 @@ public: LEX_CSTRING table_name; List fields; }; + struct func_processor_rename_table + { + Lex_ident_db old_db; + Lex_ident_table old_table; + Lex_ident_db new_db; + Lex_ident_table new_table; + }; virtual bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); @@ -3659,6 +3667,7 @@ public: bool switch_to_nullable_fields_processor(void *arg) override; bool update_vcol_processor(void *arg) override; bool rename_fields_processor(void *arg) override; + bool rename_table_processor(void *arg) override; bool check_vcol_func_processor(void *arg) override; bool set_fields_as_dependent_processor(void *arg) override { diff --git a/sql/sql_class.h b/sql/sql_class.h index 032d0bc2606..03860e5ff4e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -50,6 +50,7 @@ #include "session_tracker.h" #include "backup.h" #include "xa.h" +#include "scope.h" extern "C" void set_thd_stage_info(void *thd, diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 68dd3379d64..0ee775687f9 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -241,6 +241,8 @@ static bool compare_table_with_partition(THD *thd, TABLE *table, part_create_info.row_type= table->s->row_type; } + part_create_info.table= part_table; + /* NOTE: ha_blackhole does not support check_if_compatible_data, so this always fail for blackhole tables. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2119b98a0a2..64c142e6df3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7874,8 +7874,12 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, { if (!tmp_new_field->field->vcol_info) DBUG_RETURN(false); - if (!field->vcol_info->is_equal(tmp_new_field->field->vcol_info)) + bool err; + if (!field->vcol_info->is_equivalent(thd, table->s, create_info->table->s, + tmp_new_field->field->vcol_info, err)) DBUG_RETURN(false); + if (err) + DBUG_RETURN(true); } /* diff --git a/sql/table.cc b/sql/table.cc index 11564e85af0..b18ee64f480 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3542,6 +3542,27 @@ bool Virtual_column_info::cleanup_session_expr() } +bool +Virtual_column_info::is_equivalent(THD *thd, TABLE_SHARE *share, TABLE_SHARE *vcol_share, + const Virtual_column_info* vcol, bool &error) const +{ + error= true; + Item *cmp_expr= vcol->expr->build_clone(thd); + if (!cmp_expr) + return false; + Item::func_processor_rename_table param; + param.old_db= Lex_ident_db(vcol_share->db); + param.old_table= Lex_ident_table(vcol_share->table_name); + param.new_db= Lex_ident_db(share->db); + param.new_table= Lex_ident_table(share->table_name); + cmp_expr->walk(&Item::rename_table_processor, 1, ¶m); + + error= false; + return type_handler() == vcol->type_handler() + && is_stored() == vcol->is_stored() + && expr->eq(cmp_expr, true); +} + class Vcol_expr_context { From 0dcd30197ade55b7afb248e99b29b80ead99b3e2 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:58 +0300 Subject: [PATCH 24/41] MDEV-25654 Unexpected ER_CRASHED_ON_USAGE and Assertion `limit >= trx_id' failed in purge_node_t::skip For fast alter partition ALTER lost hash fields in frm field count. mysql_prepare_create_table() did not call add_hash_field() because the logic of ALTER-ing field types implies automatic promotion/demotion to/from hash index. So we don't pass hash algorithm to mysql_prepare_create_table() and let it decide itself, but it cannot decide it correctly for fast alter partition. So now mysql_prepare_alter_table() is a bit more sophisticated on what to pass in the algorithm. If not changed any fields it will force mysql_prepare_create_table() to re-add hash fields by setting HA_KEY_ALG_HASH. The problem with the original logic is mysql_prepare_alter_table() does not care 100% about hash property so the decision is blurred between mysql_prepare_alter_table() and mysql_prepare_create_table(). --- mysql-test/main/long_unique_bugs.result | 12 ++++++++++++ mysql-test/main/long_unique_bugs.test | 15 +++++++++++++++ sql/sql_table.cc | 15 ++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result index c85f5d5b21e..1caec209d9f 100644 --- a/mysql-test/main/long_unique_bugs.result +++ b/mysql-test/main/long_unique_bugs.result @@ -729,4 +729,16 @@ alter table t1 enable keys; insert into t1 values (2); ERROR 23000: Duplicate entry '2' for key 'i' drop table t1; +# +# MDEV-25654 Unexpected ER_CRASHED_ON_USAGE and Assertion `limit >= trx_id' failed in purge_node_t::skip +# +create table t1 (a int, unique using hash (a)) engine=innodb +partition by range(a) ( +partition p1 values less than (2), +partition p2 values less than (101) +); +insert into t1 select seq from seq_1_to_100; +alter table t1 add partition (partition p3 values less than (maxvalue)); +alter table t1 force; +drop table t1; # End of 10.5 tests diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index 2f85328bda3..6ad59fe6495 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -706,4 +706,19 @@ alter table t1 enable keys; insert into t1 values (2); drop table t1; +--echo # +--echo # MDEV-25654 Unexpected ER_CRASHED_ON_USAGE and Assertion `limit >= trx_id' failed in purge_node_t::skip +--echo # +create table t1 (a int, unique using hash (a)) engine=innodb +partition by range(a) ( + partition p1 values less than (2), + partition p2 values less than (101) +); +insert into t1 select seq from seq_1_to_100; + +alter table t1 add partition (partition p3 values less than (maxvalue)); +alter table t1 force; + +drop table t1; + --echo # End of 10.5 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 64c142e6df3..e744ab78a2f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9264,7 +9264,20 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, LEX_CSTRING tmp_name; bzero((char*) &key_create_info, sizeof(key_create_info)); if (key_info->algorithm == HA_KEY_ALG_LONG_HASH) - key_info->algorithm= HA_KEY_ALG_UNDEF; + key_info->algorithm= (alter_info->flags & ALTER_CHANGE_COLUMN) ? + HA_KEY_ALG_UNDEF : HA_KEY_ALG_HASH; + /* + This one goes to mysql_prepare_create_table(): + + key_info->algorithm= key->key_create_info.algorithm; + + For HA_KEY_ALG_LONG_HASH if we didn't change ANY column, we pass + HA_KEY_ALG_HASH to ensure mysql_prepare_create_table() does add_hash_field(). + This protects fast alter partition from losing hash properties. + In case of any column changes we drop algorithm to HA_KEY_ALG_UNDEF and + let decide mysql_prepare_create_table() if the hash field is needed + depending on new types. + */ key_create_info.algorithm= key_info->algorithm; /* We copy block size directly as some engines, like Area, sets this From e760a6dc1ceab5b0f2809d194af0f321fa12b933 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 25/41] MDEV-35343 ha_heap: recover the cursor after failed ha_update_row --- storage/heap/hp_update.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/storage/heap/hp_update.c b/storage/heap/hp_update.c index da83a9c76a8..ad56ca979de 100644 --- a/storage/heap/hp_update.c +++ b/storage/heap/hp_update.c @@ -21,7 +21,8 @@ int heap_update(HP_INFO *info, const uchar *old, const uchar *heap_new) { HP_KEYDEF *keydef, *end, *p_lastinx; - uchar *pos; + uchar *pos, *recovery_ptr; + struct st_hp_hash_info *recovery_hash_ptr; my_bool auto_key_changed= 0, key_changed= 0; HP_SHARE *share= info->s; DBUG_ENTER("heap_update"); @@ -34,6 +35,10 @@ int heap_update(HP_INFO *info, const uchar *old, const uchar *heap_new) if (--(share->records) < share->blength >> 1) share->blength>>= 1; share->changed=1; + // Save the cursor position to recover if insert fails. + recovery_ptr= info->current_ptr; + recovery_hash_ptr= info->current_hash_ptr; + p_lastinx= share->keydef + info->lastinx; for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++) { @@ -84,6 +89,8 @@ int heap_update(HP_INFO *info, const uchar *old, const uchar *heap_new) } keydef--; } + info->current_ptr= recovery_ptr; + info->current_hash_ptr= recovery_hash_ptr; } if (++(share->records) == share->blength) share->blength+= share->blength; From e1e1e50bbaf3fd96ac0b5ca4fcd28a458132e9bd Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 26/41] MDEV-35343 DML debug logging Usage: mtr --mysqld=--debug=d,dml,query:i:o,/tmp/dml.log Example output: T@6 : dispatch_command: query: insert into t1 values ('a') T@6 : handler::ha_write_row: exit: INSERT: t1(a) = 0 T@6 : dispatch_command: query: alter ignore table t1 add unique index (data) T@6 : handler::ha_write_row: exit: INSERT: t1(a) = 0 T@6 : dispatch_command: query: alter ignore table t1 add unique index (data) T@6 : handler::ha_write_row: exit: INSERT: t1(a) = 0 T@6 : dispatch_command: query: replace into t1 values ('b'), ('c'), ('a'), ('b') T@6 : handler::ha_write_row: exit: INSERT: t1(b) = 0 T@6 : handler::ha_write_row: exit: INSERT: t1(c) = 0 T@6 : handler::ha_write_row: exit: INSERT: t1(a) = 121 T@6 : write_record: exit: DELETE: t1(a) = 0 T@6 : handler::ha_write_row: exit: INSERT: t1(a) = 0 T@6 : handler::ha_write_row: exit: INSERT: t1(b) = 121 T@6 : write_record: exit: DELETE: t1(b) = 0 T@6 : handler::ha_write_row: exit: INSERT: t1(b) = 0 --- sql/filesort.cc | 70 +++++++++++++++++++++++++++---------------------- sql/handler.cc | 4 +++ sql/handler.h | 4 +++ 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/sql/filesort.cc b/sql/filesort.cc index 822c52700a6..af03067257c 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -634,13 +634,6 @@ static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count, } #ifndef DBUG_OFF - -/* Buffer where record is returned */ -char dbug_print_row_buff[512]; - -/* Temporary buffer for printing a column */ -char dbug_print_row_buff_tmp[512]; - /* Print table's current row into a buffer and return a pointer to it. @@ -653,37 +646,53 @@ char dbug_print_row_buff_tmp[512]; Only columns in table->read_set are printed */ -const char* dbug_print_table_row(TABLE *table) +const char* dbug_print_row(TABLE *table, const uchar *rec, bool print_names) { Field **pfield; - String tmp(dbug_print_row_buff_tmp, - sizeof(dbug_print_row_buff_tmp),&my_charset_bin); + const size_t alloc_size= 512; + char *row_buff= (char *) alloc_root(&table->mem_root, alloc_size); + char *row_buff_tmp= (char *) alloc_root(&table->mem_root, alloc_size); + String tmp(row_buff_tmp, alloc_size, &my_charset_bin); + String output(row_buff, alloc_size, &my_charset_bin); - String output(dbug_print_row_buff, sizeof(dbug_print_row_buff), - &my_charset_bin); + auto move_back_lambda= [table, rec]() mutable { + table->move_fields(table->field, table->record[0], rec); + }; + auto move_back_guard= make_scope_exit(move_back_lambda, false); + + if (rec != table->record[0]) + { + table->move_fields(table->field, rec, table->record[0]); + move_back_guard.engage(); + } + + SCOPE_VALUE(table->read_set, (table->read_set && table->write_set) ? + table->write_set : table->read_set); output.length(0); output.append(table->alias); output.append("("); bool first= true; - - for (pfield= table->field; *pfield ; pfield++) + if (print_names) { - if (table->read_set && !bitmap_is_set(table->read_set, (*pfield)->field_index)) - continue; - - if (first) - first= false; - else - output.append(","); + for (pfield= table->field; *pfield ; pfield++) + { + if (table->read_set && !bitmap_is_set(table->read_set, (*pfield)->field_index)) + continue; - output.append((*pfield)->field_name.str ? - (*pfield)->field_name.str: "NULL"); + if (first) + first= false; + else + output.append(", "); + + output.append((*pfield)->field_name.str ? + (*pfield)->field_name.str: "NULL"); + } + + output.append(")=("); + first= true; } - output.append(")=("); - - first= true; for (pfield= table->field; *pfield ; pfield++) { Field *field= *pfield; @@ -694,7 +703,7 @@ const char* dbug_print_table_row(TABLE *table) if (first) first= false; else - output.append(","); + output.append(", "); if (field->is_null()) output.append("NULL"); @@ -713,12 +722,9 @@ const char* dbug_print_table_row(TABLE *table) } -const char* dbug_print_row(TABLE *table, uchar *rec) +const char* dbug_print_table_row(TABLE *table) { - table->move_fields(table->field, rec, table->record[0]); - const char* ret= dbug_print_table_row(table); - table->move_fields(table->field, table->record[0], rec); - return ret; + return dbug_print_row(table, table->record[0]); } diff --git a/sql/handler.cc b/sql/handler.cc index 38453b5e2a7..50bcf86f25c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7350,6 +7350,7 @@ int handler::ha_write_row(const uchar *buf) TABLE_IO_WAIT(tracker, PSI_TABLE_WRITE_ROW, MAX_KEY, error, { error= write_row(buf); }) + DBUG_PRINT("dml", ("INSERT: %s = %d", dbug_print_row(table, buf, false), error)); MYSQL_INSERT_ROW_DONE(error); if (likely(!error)) @@ -7410,6 +7411,8 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) TABLE_IO_WAIT(tracker, PSI_TABLE_UPDATE_ROW, active_index, 0, { error= update_row(old_data, new_data);}) + DBUG_PRINT("dml", ("UPDATE: %s => %s = %d", dbug_print_row(table, old_data, false), + dbug_print_row(table, new_data, false), error)); MYSQL_UPDATE_ROW_DONE(error); if (likely(!error)) @@ -7489,6 +7492,7 @@ int handler::ha_delete_row(const uchar *buf) TABLE_IO_WAIT(tracker, PSI_TABLE_DELETE_ROW, active_index, error, { error= delete_row(buf);}) + DBUG_PRINT("dml", ("DELETE: %s = %d", dbug_print_row(table, buf, false), error)); MYSQL_DELETE_ROW_DONE(error); if (likely(!error)) { diff --git a/sql/handler.h b/sql/handler.h index ad1cbaff5b7..c06c27b08c9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -5322,4 +5322,8 @@ bool non_existing_table_error(int error); int get_select_field_pos(Alter_info *alter_info, int select_field_count, bool versioned); + +#ifndef DBUG_OFF +const char* dbug_print_row(TABLE *table, const uchar *rec, bool print_names= true); +#endif /* DBUG_OFF */ #endif /* HANDLER_INCLUDED */ From 78c192644c093ec2968e5748cd1d66b66dfbc1a9 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 27/41] MDEV-35343 unexpected replace behaviour when long unique index on system versioned table For versioned table REPLACE first tries to insert a row, if it gets duplicate key error and optimization is possible it does UPDATE + INSERT history. If optimization is not possible it goes normal branch for UPDATE to history and repeats the cycle of INSERT. The failure was in normal branch when we tried UPDATE to history but such history already exists from previous cycles. There is no such failures in optimized branch because vers_insert_history_row() already ignores duplicates. The fix ignores duplicate errors for UPDATE to history and does DELETE instead. --- mysql-test/suite/versioning/r/replace.result | 16 +++++++++++++++ mysql-test/suite/versioning/t/replace.test | 15 ++++++++++++++ sql/sql_insert.cc | 21 ++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result index 8ac4047c5ff..c64f42ee7cf 100644 --- a/mysql-test/suite/versioning/r/replace.result +++ b/mysql-test/suite/versioning/r/replace.result @@ -27,7 +27,9 @@ id x current 1 2 0 1 3 1 drop table t; +# # MDEV-15645 Assertion `table->insert_values' failed in write_record upon REPLACE into a view with underlying versioned table +# create or replace table t1 (a int, b int, primary key (a), unique(b)) with system versioning; insert into t1 values (1,1); create or replace table t2 (c int); @@ -48,7 +50,9 @@ INSERT INTO t1 () VALUES (),(),(),(),(),(); UPDATE IGNORE t1 SET f = 1; REPLACE t1 SELECT * FROM t1; DROP TABLE t1; +# # MDEV-22540 ER_DUP_ENTRY upon REPLACE or Assertion failed +# set timestamp=1589245268.41934; create table t1 (a int primary key) with system versioning; insert into t1 values (1),(2); @@ -72,3 +76,15 @@ Warnings: Warning 1062 Duplicate entry '1' for key 'a' load data infile '15330.data' replace into table t1 (a,b,c); drop table t1; +# +# MDEV-35343 unexpected replace behaviour when long unique index on system versioned table +# +create table t1 (data char(10)); +insert into t1 values ('o'); +alter ignore table t1 add unique index (data); +alter ignore table t1 add unique index (data); +Warnings: +Note 1831 Duplicate index `data_2`. This is deprecated and will be disallowed in a future release +alter table t1 add system versioning; +replace into t1 values ('o'), ('o'); +drop table t1; diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test index d69eebd1b9c..c10b6aa443d 100644 --- a/mysql-test/suite/versioning/t/replace.test +++ b/mysql-test/suite/versioning/t/replace.test @@ -35,7 +35,9 @@ replace t values (1, 3); select *, current_row(row_end) as current from t for system_time all order by x; drop table t; +--echo # --echo # MDEV-15645 Assertion `table->insert_values' failed in write_record upon REPLACE into a view with underlying versioned table +--echo # create or replace table t1 (a int, b int, primary key (a), unique(b)) with system versioning; insert into t1 values (1,1); create or replace table t2 (c int); @@ -59,7 +61,9 @@ UPDATE IGNORE t1 SET f = 1; REPLACE t1 SELECT * FROM t1; DROP TABLE t1; +--echo # --echo # MDEV-22540 ER_DUP_ENTRY upon REPLACE or Assertion failed +--echo # set timestamp=1589245268.41934; create table t1 (a int primary key) with system versioning; insert into t1 values (1),(2); @@ -105,4 +109,15 @@ drop table t1; eval set default_storage_engine= $default_engine; --enable_query_log +--echo # +--echo # MDEV-35343 unexpected replace behaviour when long unique index on system versioned table +--echo # +create table t1 (data char(10)); +insert into t1 values ('o'); +alter ignore table t1 add unique index (data); +alter ignore table t1 add unique index (data); +alter table t1 add system versioning; +replace into t1 values ('o'), ('o'); +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 50a1a37e3ea..acc841e27f0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2126,6 +2126,9 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink) !table->file->referenced_by_foreign_key() && (!table->triggers || !table->triggers->has_delete_triggers())) { + /* + Optimized dup handling via UPDATE (and insert history for versioned). + */ if (table->versioned(VERS_TRX_ID)) { bitmap_set_bit(table->write_set, table->vers_start_field()->field_index); @@ -2160,25 +2163,39 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink) } else { + /* + Normal dup handling via DELETE (or UPDATE to history for versioned) + and repeating the cycle of INSERT. + */ if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, TRUE)) goto before_trg_err; - if (!table->versioned(VERS_TIMESTAMP)) + bool do_delete= !table->versioned(VERS_TIMESTAMP); + if (do_delete) error= table->file->ha_delete_row(table->record[1]); else { + /* Update existing row to history */ store_record(table, record[2]); restore_record(table, record[1]); table->vers_update_end(); error= table->file->ha_update_row(table->record[1], table->record[0]); restore_record(table, record[2]); + if (error == HA_ERR_FOUND_DUPP_KEY || /* Unique index, any SE */ + error == HA_ERR_FOREIGN_DUPLICATE_KEY || /* Unique index, InnoDB */ + error == HA_ERR_RECORD_IS_THE_SAME) /* No index */ + { + /* Such history row was already generated from previous cycles */ + error= table->file->ha_delete_row(table->record[1]); + do_delete= true; + } } if (unlikely(error)) goto err; - if (!table->versioned(VERS_TIMESTAMP)) + if (do_delete) info->deleted++; else info->updated++; From 4a58d1085dfc7e2dea7affdd7e389493fc0fd430 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 28/41] MDEV-35612 EXCHANGE PARTITION does not work for tables with unique blobs mysql_compare_tables() failed because of no long hash index generated fields in prepared tmp_create_info. In comparison we should skip these fields in the original table by: 1. skipping INVISIBLE_SYSTEM fields; 2. getting key_info from table->s instead of table as TABLE_SHARE contains unwrapped key_info. --- mysql-test/main/partition_exchange.result | 10 ++++++++++ mysql-test/main/partition_exchange.test | 14 ++++++++++++++ sql/sql_table.cc | 22 +++++++++++++++++----- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/partition_exchange.result b/mysql-test/main/partition_exchange.result index 999517f4028..c9169c5c818 100644 --- a/mysql-test/main/partition_exchange.result +++ b/mysql-test/main/partition_exchange.result @@ -1343,3 +1343,13 @@ create or replace table t2_working like t2; alter table t2_working remove partitioning; alter table t2 exchange partition p1 with table t2_working; drop tables t1, t1_working, t2, t2_working; +# +# MDEV-35612 EXCHANGE PARTITION does not work for tables with unique blobs +# +create table t (a int, b text, unique (b), unique(a, b)) partition by list (a) (partition p0 values in (1,2), partition pdef default); +create table tp (a int, b text, c int invisible, unique (b), unique(a, b)); +alter table t exchange partition p0 with table tp; +ERROR HY000: Tables have different definitions +create or replace table tp (a int, b text, unique (b), unique(a, b)); +alter table t exchange partition p0 with table tp; +drop table t, tp; diff --git a/mysql-test/main/partition_exchange.test b/mysql-test/main/partition_exchange.test index e92b8dfff5c..767f682ea0d 100644 --- a/mysql-test/main/partition_exchange.test +++ b/mysql-test/main/partition_exchange.test @@ -586,3 +586,17 @@ alter table t2 exchange partition p1 with table t2_working; # Cleanup drop tables t1, t1_working, t2, t2_working; + +--echo # +--echo # MDEV-35612 EXCHANGE PARTITION does not work for tables with unique blobs +--echo # +create table t (a int, b text, unique (b), unique(a, b)) partition by list (a) (partition p0 values in (1,2), partition pdef default); +create table tp (a int, b text, c int invisible, unique (b), unique(a, b)); +--error ER_TABLES_DIFFERENT_METADATA +alter table t exchange partition p0 with table tp; + +create or replace table tp (a int, b text, unique (b), unique(a, b)); +alter table t exchange partition p0 with table tp; + +# cleanup +drop table t, tp; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e744ab78a2f..3563c0fa982 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7852,7 +7852,16 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, DBUG_RETURN(1); /* Some very basic checks. */ - if (table->s->fields != alter_info->create_list.elements || + uint fields= table->s->fields; + + /* There is no field count on system-invisible fields, count them. */ + for (Field **f_ptr= table->field; *f_ptr; f_ptr++) + { + if ((*f_ptr)->invisible >= INVISIBLE_SYSTEM) + fields--; + } + + if (fields != alter_info->create_list.elements || table->s->db_type() != create_info->db_type || table->s->tmp_table || (table->s->row_type != create_info->row_type)) @@ -7863,6 +7872,9 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, for (Field **f_ptr= table->field; *f_ptr; f_ptr++) { Field *field= *f_ptr; + /* Skip hidden generated field like long hash index. */ + if (field->invisible >= INVISIBLE_SYSTEM) + continue; Create_field *tmp_new_field= tmp_new_field_it++; /* Check that NULL behavior is the same. */ @@ -7915,13 +7927,13 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, DBUG_RETURN(false); /* Go through keys and check if they are compatible. */ - KEY *table_key; - KEY *table_key_end= table->key_info + table->s->keys; + KEY *table_key= table->s->key_info; + KEY *table_key_end= table_key + table->s->keys; KEY *new_key; KEY *new_key_end= key_info_buffer + key_count; /* Step through all keys of the first table and search matching keys. */ - for (table_key= table->key_info; table_key < table_key_end; table_key++) + for (; table_key < table_key_end; table_key++) { /* Search a key with the same name. */ for (new_key= key_info_buffer; new_key < new_key_end; new_key++) @@ -7964,7 +7976,7 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, for (new_key= key_info_buffer; new_key < new_key_end; new_key++) { /* Search a key with the same name. */ - for (table_key= table->key_info; table_key < table_key_end; table_key++) + for (table_key= table->s->key_info; table_key < table_key_end; table_key++) { if (!lex_string_cmp(system_charset_info, &table_key->name, &new_key->name)) From ab90eaad792996d10c5c67cde09cffa3d5baebbd Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 29/41] MDEV-22695 Server crashes in heap_rnext upon DELETE from a HEAP table Quick read record uses different handler (H1) for finding records. It cannot use ha_delete_row() handler (H2) as it is different search mode: inited == INDEX for H1, inited == RND for H2. So, read handler H1 uses index while write handler H2 uses random access. For going next record in H1 there is info->last_pos optimization for stepping index via tree_search_next(). This optimization can work with deleted rows only if delete is conducted in the same handler, there is: 67 int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, 68 const uchar *record, uchar *recpos, int flag) 69 { ... 74 if (flag) 75 info->last_pos= NULL; /* For heap_rnext/heap_rprev */ But this cannot work for different handler. So, last_pos in H1 after delete in H2 contains stale info->parents array and last_pos points into that parents. In the specific test case last_pos' parent is already freed node and tree_search_next() steps into it. The fix invalidates local savings of info->parents and info->last_pos based on key_version. Record deletion increments share->key_version in H2, so in H1 we know the tree might be changed. Another good measure would be to use H1 for delete. But this is bigger refactoring than just bug fixing. --- mysql-test/suite/heap/heap.result | 7 +++++++ mysql-test/suite/heap/heap.test | 9 +++++++++ storage/heap/hp_rnext.c | 4 +++- storage/heap/hp_rprev.c | 3 ++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/heap/heap.result b/mysql-test/suite/heap/heap.result index 67641d51b02..11c50d97475 100644 --- a/mysql-test/suite/heap/heap.result +++ b/mysql-test/suite/heap/heap.result @@ -877,3 +877,10 @@ DELETE FROM t1 WHERE ts = 1 AND color = 'GREEN'; SELECT * from t1 WHERE ts = 1 AND color = 'GREEN'; id color ts DROP TABLE t1; +# +# MDEV-22695 Server crashes in heap_rnext upon DELETE from a HEAP table +# +CREATE TABLE t1 (a VARCHAR(128), b VARCHAR(32), KEY(a) USING BTREE, KEY(b) USING BTREE) ENGINE=HEAP; +INSERT INTO t1 VALUES ('foo',NULL),('m','b'),(6,'j'),('bar','qux'),(NULL,NULL); +DELETE FROM t1 WHERE a <=> 'm' OR b <=> NULL; +DROP TABLE t1; diff --git a/mysql-test/suite/heap/heap.test b/mysql-test/suite/heap/heap.test index ef950da5484..02a2586f605 100644 --- a/mysql-test/suite/heap/heap.test +++ b/mysql-test/suite/heap/heap.test @@ -659,3 +659,12 @@ INSERT INTO t1 VALUES("7","GREEN", 2); DELETE FROM t1 WHERE ts = 1 AND color = 'GREEN'; SELECT * from t1 WHERE ts = 1 AND color = 'GREEN'; DROP TABLE t1; + +--echo # +--echo # MDEV-22695 Server crashes in heap_rnext upon DELETE from a HEAP table +--echo # +CREATE TABLE t1 (a VARCHAR(128), b VARCHAR(32), KEY(a) USING BTREE, KEY(b) USING BTREE) ENGINE=HEAP; +INSERT INTO t1 VALUES ('foo',NULL),('m','b'),(6,'j'),('bar','qux'),(NULL,NULL); +DELETE FROM t1 WHERE a <=> 'm' OR b <=> NULL; +# Cleanup +DROP TABLE t1; diff --git a/storage/heap/hp_rnext.c b/storage/heap/hp_rnext.c index f227ce4d274..ac21ed83da2 100644 --- a/storage/heap/hp_rnext.c +++ b/storage/heap/hp_rnext.c @@ -46,7 +46,7 @@ int heap_rnext(HP_INFO *info, uchar *record) &info->last_pos, offsetof(TREE_ELEMENT, left)); } } - else if (info->last_pos) + else if (info->last_pos && info->key_version == info->s->key_version) { /* We enter this branch for non-DELETE queries after heap_rkey() @@ -72,6 +72,7 @@ int heap_rnext(HP_INFO *info, uchar *record) */ pos= tree_search_edge(&keyinfo->rb_tree, info->parents, &info->last_pos, offsetof(TREE_ELEMENT, left)); + info->key_version= info->s->key_version; } else { @@ -87,6 +88,7 @@ int heap_rnext(HP_INFO *info, uchar *record) info->last_find_flag= HA_READ_KEY_OR_NEXT; pos = tree_search_key(&keyinfo->rb_tree, info->lastkey, info->parents, &info->last_pos, info->last_find_flag, &custom_arg); + info->key_version= info->s->key_version; } if (pos) { diff --git a/storage/heap/hp_rprev.c b/storage/heap/hp_rprev.c index 1d9420ba8b6..cc81d179570 100644 --- a/storage/heap/hp_rprev.c +++ b/storage/heap/hp_rprev.c @@ -46,7 +46,7 @@ int heap_rprev(HP_INFO *info, uchar *record) &info->last_pos, offsetof(TREE_ELEMENT, right)); } } - else if (info->last_pos) + else if (info->last_pos && info->key_version == info->s->key_version) pos = tree_search_next(&keyinfo->rb_tree, &info->last_pos, offsetof(TREE_ELEMENT, right), offsetof(TREE_ELEMENT, left)); @@ -58,6 +58,7 @@ int heap_rprev(HP_INFO *info, uchar *record) info->last_find_flag= HA_READ_KEY_OR_PREV; pos = tree_search_key(&keyinfo->rb_tree, info->lastkey, info->parents, &info->last_pos, info->last_find_flag, &custom_arg); + info->key_version= info->s->key_version; } if (pos) { From 0fa1a7cc6af2d1ca90363f73d6bff97c805caf22 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 13 Jan 2025 15:40:59 +0300 Subject: [PATCH 30/41] MDEV-28130 MariaDB SEGV issue at tree_search_next In case of error last_pos points to null_element and there is no any other children. tree_search_next() walks the children from last_pos until the leaves (null_element) ignoring the case the topmost parent in search state is the leaf itself. --- mysql-test/suite/heap/heap.result | 12 ++++++++++++ mysql-test/suite/heap/heap.test | 10 ++++++++++ mysys/tree.c | 3 +++ 3 files changed, 25 insertions(+) diff --git a/mysql-test/suite/heap/heap.result b/mysql-test/suite/heap/heap.result index 11c50d97475..d42e898a0ae 100644 --- a/mysql-test/suite/heap/heap.result +++ b/mysql-test/suite/heap/heap.result @@ -884,3 +884,15 @@ CREATE TABLE t1 (a VARCHAR(128), b VARCHAR(32), KEY(a) USING BTREE, KEY(b) USING INSERT INTO t1 VALUES ('foo',NULL),('m','b'),(6,'j'),('bar','qux'),(NULL,NULL); DELETE FROM t1 WHERE a <=> 'm' OR b <=> NULL; DROP TABLE t1; +# +# MDEV-28130 MariaDB SEGV issue at tree_search_next +# +CREATE TABLE v(t1 INT, pk INT, KEY(t1), KEY pk using btree (pk), KEY v using btree(t1, pk)) engine=memory; +HANDLER v OPEN; +HANDLER v READ t1=(2) limit 3; +t1 pk +HANDLER v READ pk PREV; +t1 pk +HANDLER v READ pk PREV; +t1 pk +drop table v; diff --git a/mysql-test/suite/heap/heap.test b/mysql-test/suite/heap/heap.test index 02a2586f605..97784aefc0f 100644 --- a/mysql-test/suite/heap/heap.test +++ b/mysql-test/suite/heap/heap.test @@ -668,3 +668,13 @@ INSERT INTO t1 VALUES ('foo',NULL),('m','b'),(6,'j'),('bar','qux'),(NULL,NULL); DELETE FROM t1 WHERE a <=> 'm' OR b <=> NULL; # Cleanup DROP TABLE t1; + +--echo # +--echo # MDEV-28130 MariaDB SEGV issue at tree_search_next +--echo # +CREATE TABLE v(t1 INT, pk INT, KEY(t1), KEY pk using btree (pk), KEY v using btree(t1, pk)) engine=memory; +HANDLER v OPEN; +HANDLER v READ t1=(2) limit 3; +HANDLER v READ pk PREV; +HANDLER v READ pk PREV; +drop table v; diff --git a/mysys/tree.c b/mysys/tree.c index cd44f779e6f..db0442fa827 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -494,6 +494,9 @@ void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs, int r_offs) { TREE_ELEMENT *x= **last_pos; + + if (x == &null_element) + return NULL; if (ELEMENT_CHILD(x, r_offs) != &null_element) { From a5174aaffb8f22b211945170588828557dbdb211 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 14 Jan 2025 22:42:18 +0200 Subject: [PATCH 31/41] MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself (Variant 2: use stack for buffers) my_malloc_size_cb_func() has a call to thd->alloc() to produce an error message. thd->alloc() calls alloc_root(), so one can end up with this stack trace: alloc_root() THD::alloc() my_malloc_size_cb_func() my_malloc() alloc_root() where alloc_root() calls itself. This is a problem, as alloc_root() is not reenterable. Fixed this by switching my_malloc_size_cb_func() to use space on the stack instead. --- mysql-test/main/errors.result | 13 +++++++++++++ mysql-test/main/errors.test | 20 ++++++++++++++++++++ sql/mysqld.cc | 18 +++++------------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/mysql-test/main/errors.result b/mysql-test/main/errors.result index baa2e0ad3c0..5b469b640f8 100644 --- a/mysql-test/main/errors.result +++ b/mysql-test/main/errors.result @@ -231,3 +231,16 @@ Error 1327 Undeclared variable: foo Error 1305 PROCEDURE P1 does not exist drop procedure P1; # End of 10.4 tests +# +# MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself +# +CREATE TEMPORARY TABLE t1 (a INT,b INT); +INSERT INTO t1 VALUES (1,1),(2,2); +SET +@tmp=@@max_session_mem_used, +max_session_mem_used=8192; +SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; +ERROR HY000: The MariaDB server is running with the --max-session-mem-used=8192 option so it cannot execute this statement +DROP TABLE t1; +SET max_session_mem_used=@tmp; +# End of 10.6 tests diff --git a/mysql-test/main/errors.test b/mysql-test/main/errors.test index cc5cad2a68e..87d6d2fdec9 100644 --- a/mysql-test/main/errors.test +++ b/mysql-test/main/errors.test @@ -284,3 +284,23 @@ show warnings; drop procedure P1; -- echo # End of 10.4 tests + + +--echo # +--echo # MDEV-35828: Assertion fails in alloc_root() when memory causes it to call itself +--echo # +CREATE TEMPORARY TABLE t1 (a INT,b INT); +INSERT INTO t1 VALUES (1,1),(2,2); + +SET + @tmp=@@max_session_mem_used, + max_session_mem_used=8192; + +--error ER_OPTION_PREVENTS_STATEMENT +SELECT * FROM (t1 AS t2 LEFT JOIN t1 AS t3 USING (a)),t1; + +DROP TABLE t1; +SET max_session_mem_used=@tmp; + + +--echo # End of 10.6 tests diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c798956910f..d6dd8a566af 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3513,22 +3513,14 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific) LOCK_thd_kill here (the limit will be enforced on the next allocation). */ if (!mysql_mutex_trylock(&thd->LOCK_thd_kill)) { - char buf[50], *buf2; + char buf[50], buf2[256]; thd->set_killed_no_mutex(KILL_QUERY); my_snprintf(buf, sizeof(buf), "--max-session-mem-used=%llu", thd->variables.max_mem_used); - if ((buf2= (char*) thd->alloc(256))) - { - my_snprintf(buf2, 256, - ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); - thd->set_killed_no_mutex(KILL_QUERY, - ER_OPTION_PREVENTS_STATEMENT, buf2); - } - else - { - thd->set_killed_no_mutex(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, - "--max-session-mem-used"); - } + my_snprintf(buf2, 256, + ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf); + thd->set_killed_no_mutex(KILL_QUERY, + ER_OPTION_PREVENTS_STATEMENT, buf2); mysql_mutex_unlock(&thd->LOCK_thd_kill); } } From 78157c4765f2c086fabe183d51d7734ecffdbdd8 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Tue, 14 Jan 2025 17:47:08 +1100 Subject: [PATCH 32/41] MDEV-35840 Eliminate -warray-bounds triggered by TABLE_SHARE::db_type() The warnings are triggered with -O3 --- sql/sql_base.cc | 3 ++- sql/sql_partition.cc | 27 ++++++++++++++++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5c03ba3d42d..aaa86e7bfa0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8953,8 +8953,9 @@ my_bool mysql_rm_tmp_tables(void) memcpy(path_copy, path, path_len - ext_len); path_copy[path_len - ext_len]= 0; init_tmp_table_share(thd, &share, "", 0, "", path_copy); + handlerton *ht= share.db_type(); if (!open_table_def(thd, &share)) - share.db_type()->drop_table(share.db_type(), path_copy); + ht->drop_table(share.db_type(), path_copy); free_table_share(&share); } /* diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 6228991d46c..e17f6e5a00a 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -721,9 +721,11 @@ static bool handle_list_of_fields(THD *thd, List_iterator it, } else { - if (table->s->db_type()->partition_flags && - (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) && - (table->s->db_type()->partition_flags() & HA_CAN_PARTITION)) + handlerton *ht= table->s->db_type(); + if (ht->partition_flags && + ((ht->partition_flags() & + (HA_USE_AUTO_PARTITION | HA_CAN_PARTITION)) == + (HA_USE_AUTO_PARTITION | HA_CAN_PARTITION))) { /* This engine can handle automatic partitioning and there is no @@ -1927,6 +1929,7 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) bool result= TRUE; partition_info *part_info= table->part_info; enum_column_usage saved_column_usage= thd->column_usage; + handlerton *ht; DBUG_ENTER("fix_partition_func"); if (part_info->fixed) @@ -2056,8 +2059,9 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) goto end; if (unlikely(check_primary_key(table))) goto end; - if (unlikely((!(table->s->db_type()->partition_flags && - (table->s->db_type()->partition_flags() & HA_CAN_PARTITION_UNIQUE))) && + ht= table->s->db_type(); + if (unlikely((!(ht->partition_flags && + (ht->partition_flags() & HA_CAN_PARTITION_UNIQUE))) && check_unique_keys(table))) goto end; if (unlikely(set_up_partition_bitmaps(thd, part_info))) @@ -2713,12 +2717,14 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields) { Field **fld; partition_info *part_info= table->part_info; + handlerton *ht; DBUG_ENTER("partition_key_modified"); if (!part_info) DBUG_RETURN(FALSE); - if (table->s->db_type()->partition_flags && - (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY)) + ht= table->s->db_type(); + if (ht->partition_flags && + (ht->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY)) DBUG_RETURN(FALSE); for (fld= part_info->full_part_field_array; *fld; fld++) if (bitmap_is_set(fields, (*fld)->field_index)) @@ -4927,11 +4933,10 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, if default partitioning is used. */ + handlerton *ht= table->s->db_type(); if (tab_part_info->part_type != HASH_PARTITION || - ((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) && - !tab_part_info->use_default_num_partitions) || - ((!(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)) && - tab_part_info->use_default_num_partitions)) + !(ht->partition_flags() & HA_USE_AUTO_PARTITION) == + tab_part_info->use_default_num_partitions) { my_error(ER_REORG_NO_PARAM_ERROR, MYF(0)); goto err; From 86b257f8705031730f011998a7e664cf981b39b6 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Thu, 16 Jan 2025 10:35:44 -0500 Subject: [PATCH 33/41] MDEV-35632 HandlerSocket uses deprecated C++98 auto_ptr Change uses of auto_ptr to unique_ptr --- plugin/handler_socket/client/hslongrun.cpp | 4 ++-- plugin/handler_socket/client/hstest.cpp | 4 ++-- plugin/handler_socket/handlersocket/database.cpp | 2 +- plugin/handler_socket/handlersocket/database.hpp | 9 ++------- plugin/handler_socket/handlersocket/handlersocket.cpp | 2 +- plugin/handler_socket/handlersocket/hstcpsvr.cpp | 2 +- plugin/handler_socket/handlersocket/hstcpsvr.hpp | 2 +- plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp | 4 ++-- plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp | 2 +- plugin/handler_socket/libhsclient/hstcpcli.hpp | 7 +------ 10 files changed, 14 insertions(+), 24 deletions(-) diff --git a/plugin/handler_socket/client/hslongrun.cpp b/plugin/handler_socket/client/hslongrun.cpp index b7c02951340..a9fba1dc7c3 100644 --- a/plugin/handler_socket/client/hslongrun.cpp +++ b/plugin/handler_socket/client/hslongrun.cpp @@ -927,7 +927,7 @@ hs_longrun_main(int argc, char **argv) shared.verbose = shared.conf.get_int("verbose", 1); const int table_size = shared.conf.get_int("table_size", 10000); for (int i = 0; i < table_size; ++i) { - std::auto_ptr rec(new record_value()); + std::unique_ptr rec(new record_value()); rec->key = to_stdstring(i); shared.records.push_back_ptr(rec); } @@ -966,7 +966,7 @@ hs_longrun_main(int argc, char **argv) int id = thrs.size(); const hs_longrun_thread_hs::arg_type arg(id, e.type, e.op, e.lock, shared); - std::auto_ptr thr; + std::unique_ptr thr; if (e.hs) { thr.reset(new hs_longrun_thread_hs(arg)); } else { diff --git a/plugin/handler_socket/client/hstest.cpp b/plugin/handler_socket/client/hstest.cpp index b5551fed81c..72e8a225de9 100644 --- a/plugin/handler_socket/client/hstest.cpp +++ b/plugin/handler_socket/client/hstest.cpp @@ -561,7 +561,7 @@ hstest_thread::test_9(int test_num) flds += std::string(buf); } int connected = 0; - std::auto_ptr stmt; + std::unique_ptr stmt; string_buffer wbuf; for (int i = 0; i < num; ++i) { const double tm1 = gettimeofday_double(); @@ -1474,7 +1474,7 @@ hstest_main(int argc, char **argv) #endif const int num_thrs = shared.num_threads; typedef thread thread_type; - typedef std::auto_ptr thread_ptr; + typedef std::unique_ptr thread_ptr; typedef auto_ptrcontainer< std::vector > thrs_type; thrs_type thrs; for (int i = 0; i < num_thrs; ++i) { diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp index 0a006a42f00..9441863070c 100644 --- a/plugin/handler_socket/handlersocket/database.cpp +++ b/plugin/handler_socket/handlersocket/database.cpp @@ -175,7 +175,7 @@ struct dbcontext : public dbcontext_i, private noncopyable { THD *thd; MYSQL_LOCK *lock; bool lock_failed; - std::auto_ptr user_lock; + std::unique_ptr user_lock; int user_level_lock_timeout; bool user_level_lock_locked; bool commit_error; diff --git a/plugin/handler_socket/handlersocket/database.hpp b/plugin/handler_socket/handlersocket/database.hpp index 9e2aadf7380..87761050704 100644 --- a/plugin/handler_socket/handlersocket/database.hpp +++ b/plugin/handler_socket/handlersocket/database.hpp @@ -9,11 +9,6 @@ #ifndef DENA_DATABASE_HPP #define DENA_DATABASE_HPP -#ifdef __GNUC__ -/* auto_ptr is deprecated */ -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - #include #include #include @@ -26,10 +21,10 @@ namespace dena { struct database_i; -typedef std::auto_ptr database_ptr; +typedef std::unique_ptr database_ptr; struct dbcontext_i; -typedef std::auto_ptr dbcontext_ptr; +typedef std::unique_ptr dbcontext_ptr; struct database_i { virtual ~database_i() = default; diff --git a/plugin/handler_socket/handlersocket/handlersocket.cpp b/plugin/handler_socket/handlersocket/handlersocket.cpp index 45c9e13b2ca..c513afb7dd5 100644 --- a/plugin/handler_socket/handlersocket/handlersocket.cpp +++ b/plugin/handler_socket/handlersocket/handlersocket.cpp @@ -76,7 +76,7 @@ daemon_handlersocket_init(void *p) conf["readsize"] = to_stdstring(handlersocket_readsize); conf["accept_balance"] = to_stdstring(handlersocket_accept_balance); conf["wrlock_timeout"] = to_stdstring(handlersocket_wrlock_timeout); - std::auto_ptr ap(new daemon_handlersocket_data); + std::unique_ptr ap(new daemon_handlersocket_data); if (handlersocket_port != 0 && handlersocket_port_wr != handlersocket_port) { conf["port"] = handlersocket_port; if (handlersocket_plain_secret) { diff --git a/plugin/handler_socket/handlersocket/hstcpsvr.cpp b/plugin/handler_socket/handlersocket/hstcpsvr.cpp index 336d36422b0..72435b80331 100644 --- a/plugin/handler_socket/handlersocket/hstcpsvr.cpp +++ b/plugin/handler_socket/handlersocket/hstcpsvr.cpp @@ -115,7 +115,7 @@ hstcpsvr::start_listen() arg.cshared = &cshared; arg.vshared = &vshared; arg.worker_id = i; - std::auto_ptr< thread > thr( + std::unique_ptr< thread > thr( new thread(arg, stack_size)); threads.push_back_ptr(thr); } diff --git a/plugin/handler_socket/handlersocket/hstcpsvr.hpp b/plugin/handler_socket/handlersocket/hstcpsvr.hpp index 5fbed92402b..3bb17c9ea0b 100644 --- a/plugin/handler_socket/handlersocket/hstcpsvr.hpp +++ b/plugin/handler_socket/handlersocket/hstcpsvr.hpp @@ -44,7 +44,7 @@ struct hstcpsvr_shared_v : public mutex { }; struct hstcpsvr_i; -typedef std::auto_ptr hstcpsvr_ptr; +typedef std::unique_ptr hstcpsvr_ptr; struct hstcpsvr_i { virtual ~hstcpsvr_i() = default; diff --git a/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp b/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp index 0796546cb5e..818d7327896 100644 --- a/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp +++ b/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp @@ -451,7 +451,7 @@ hstcpsvr_worker::run_one_nb() { pollfd& pfd = pfds[nfds - 1]; if ((pfd.revents & mask_in) != 0) { - std::auto_ptr c(new hstcpsvr_conn()); + std::unique_ptr c(new hstcpsvr_conn()); c->nonblocking = true; c->readsize = cshared.readsize; c->accept(cshared); @@ -498,7 +498,7 @@ hstcpsvr_worker::run_one_ep() /* listener */ ++accept_count; DBG_EP(fprintf(stderr, "IN listener\n")); - std::auto_ptr c(new hstcpsvr_conn()); + std::unique_ptr c(new hstcpsvr_conn()); c->nonblocking = true; c->readsize = cshared.readsize; c->accept(cshared); diff --git a/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp b/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp index 25612adec0f..2a2a5083e31 100644 --- a/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp +++ b/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp @@ -14,7 +14,7 @@ namespace dena { struct hstcpsvr_worker_i; -typedef std::auto_ptr hstcpsvr_worker_ptr; +typedef std::unique_ptr hstcpsvr_worker_ptr; struct hstcpsvr_worker_arg { const hstcpsvr_shared_c *cshared; diff --git a/plugin/handler_socket/libhsclient/hstcpcli.hpp b/plugin/handler_socket/libhsclient/hstcpcli.hpp index d078bdfd533..3428c2f240e 100644 --- a/plugin/handler_socket/libhsclient/hstcpcli.hpp +++ b/plugin/handler_socket/libhsclient/hstcpcli.hpp @@ -19,11 +19,6 @@ #include "string_ref.hpp" #include "string_buffer.hpp" -#ifdef __GNUC__ -/* auto_ptr is deprecated */ -# pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - namespace dena { struct hstcpcli_filter { @@ -35,7 +30,7 @@ struct hstcpcli_filter { }; struct hstcpcli_i; -typedef std::auto_ptr hstcpcli_ptr; +typedef std::unique_ptr hstcpcli_ptr; struct hstcpcli_i { virtual ~hstcpcli_i() = default; From df602ff7fa5ed9424a1d7ebaba67b665e2f6d1f6 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 16 Jan 2025 23:04:59 +0100 Subject: [PATCH 34/41] Fix main.stack on Windows A part of the test, that tests that a frame of recursive SP takes the same amount of stack, relies on the fact that 3 calls to that SP are executed in the same OS thread. This is not guaranteed with threadpool(not with Windows native threadpool, anyway) Fix the test to execute SP calls in the same thread, as semicolon-separated batched command. --- mysql-test/main/stack.result | 1 + mysql-test/main/stack.test | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/stack.result b/mysql-test/main/stack.result index 5444381327d..d30a55cd21a 100644 --- a/mysql-test/main/stack.result +++ b/mysql-test/main/stack.result @@ -37,6 +37,7 @@ $$ call recursion(0,2,@s1); call recursion(0,3,@s2); call recursion(0,4,@s3); +$$ select @s1 > 0 && @s2 > 0 && @s3 > 0; @s1 > 0 && @s2 > 0 && @s3 > 0 1 diff --git a/mysql-test/main/stack.test b/mysql-test/main/stack.test index 2277b0f48ff..8884ad45572 100644 --- a/mysql-test/main/stack.test +++ b/mysql-test/main/stack.test @@ -40,11 +40,13 @@ begin end; $$ -delimiter ;$$ - call recursion(0,2,@s1); call recursion(0,3,@s2); call recursion(0,4,@s3); +$$ + +delimiter ;$$ + select @s1 > 0 && @s2 > 0 && @s3 > 0; if (`select @s2-@s1 <> @s3 - @s2`) From f521b8ac219102332eec99f854809e6331b3dbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 17 Jan 2025 12:34:03 +0200 Subject: [PATCH 35/41] MDEV-35723: applying non-zero offset to null pointer in INSERT row_mysql_read_blob_ref(): Correctly handle what Field_blob::store() generates for length=0. --- mysql-test/suite/innodb/r/innodb.result | 6 ++++++ mysql-test/suite/innodb/t/innodb.test | 7 +++++++ storage/innobase/row/row0mysql.cc | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index e1d99c3b731..8d6aa0332e0 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -3337,3 +3337,9 @@ Table Op Msg_type Msg_text test.t1 check status OK ALTER TABLE t1 FORCE; DROP TABLE t1; +# +# MDEV-35723: applying zero offset to null pointer on INSERT +# +CREATE TABLE t1(c TEXT(1) NOT NULL, INDEX (c)) ENGINE=InnoDB; +INSERT INTO t1 SET c=''; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index ec217715aef..73baf7ed7ba 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -2605,3 +2605,10 @@ CHECK TABLE t1; ALTER TABLE t1 FORCE; # Cleanup DROP TABLE t1; + +--echo # +--echo # MDEV-35723: applying zero offset to null pointer on INSERT +--echo # +CREATE TABLE t1(c TEXT(1) NOT NULL, INDEX (c)) ENGINE=InnoDB; +INSERT INTO t1 SET c=''; +DROP TABLE t1; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 4e7cd6b0b37..09b4bff16b9 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -244,6 +244,14 @@ row_mysql_read_blob_ref( *len = mach_read_from_n_little_endian(ref, col_len - 8); + if (!*len) { + /* Field_blob::store() if (!length) would encode both + the length and the pointer in the same area. An empty + string must be a valid (nonnull) pointer in the + collation functions that cmp_data() may invoke. */ + return ref; + } + memcpy(&data, ref + col_len - 8, sizeof data); return(data); From 350cc77fee66bf0ab6e6eabbbf6ec6012c72da99 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 26 Nov 2024 13:34:28 +0400 Subject: [PATCH 36/41] MDEV-29968 Functions in default values in tables with some character sets break SHOW CREATE (and mysqldump) Item:print_for_table_def() uses QT_TO_SYSTEM_CHARSET to print the DEFAULT expression into FRM file during CREATE TABLE. Therefore, the expression is encoded in utf8 in FRM. get_field_default_value() erroneously used field->charset() to print the DEFAULT expression at SHOW CREATE TABLE time. Fixing get_field_default_value() to use &my_charset_utf8mb4_general_ci instead. This makes DEFAULT work in the way way with: - virtual column expressions: if (field->vcol_info) { StringBuffer str(&my_charset_utf8mb4_general_ci); field->vcol_info->print(&str); - check constraint expressions: if (field->check_constraint) { StringBuffer str(&my_charset_utf8mb4_general_ci); field->check_constraint->print(&str); Additional cleanup: Fixing system_charset_info to &my_charset_utf8mb4_general_ci in a few places to make non-BMP characters work in DEFAULT, virtual column, check constraint expressions. --- client/mysqldump.c | 4 +- .../include/ctype_supplementary_chars.inc | 26 ++ mysql-test/main/ctype_utf32.result | 59 ++++- mysql-test/main/ctype_utf32.test | 9 +- .../main/ctype_utf32_not_embedded.result | 106 ++++++++ mysql-test/main/ctype_utf32_not_embedded.test | 38 +++ mysql-test/main/ddl_i18n_koi8r.result | 8 +- mysql-test/main/ddl_i18n_utf8.result | 8 +- mysql-test/main/lock_view.result | 16 +- mysql-test/main/mysql.result | 4 +- mysql-test/main/mysqldump-max.result | 24 +- mysql-test/main/mysqldump-nl.result | 4 +- mysql-test/main/mysqldump-timing.result | 4 +- mysql-test/main/mysqldump-utf8mb4.result | 2 +- mysql-test/main/mysqldump.result | 226 +++++++++--------- mysql-test/main/openssl_1.result | 6 +- mysql-test/main/trigger_wl3253.result | 4 +- .../r/mysqldump_restore_func_qualified.result | 8 +- mysql-test/suite/federated/federatedx.result | 2 +- mysql-test/suite/roles/definer.result | 14 +- .../suite/sql_sequence/mysqldump.result | 8 +- sql/item.cc | 2 +- sql/sql_show.cc | 8 +- .../connect/mysql-test/connect/r/mysql.result | 2 +- 24 files changed, 413 insertions(+), 179 deletions(-) create mode 100644 mysql-test/include/ctype_supplementary_chars.inc create mode 100644 mysql-test/main/ctype_utf32_not_embedded.result create mode 100644 mysql-test/main/ctype_utf32_not_embedded.test diff --git a/client/mysqldump.c b/client/mysqldump.c index 716e1f368e4..1cb41b66e30 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -3182,7 +3182,7 @@ static uint get_table_structure(const char *table, const char *db, char *table_t fprintf(sql_file, "SET @saved_cs_client = @@character_set_client;\n" - "SET character_set_client = utf8;\n" + "SET character_set_client = utf8mb4;\n" "/*!50001 CREATE VIEW %s AS SELECT\n", result_table); @@ -3250,7 +3250,7 @@ static uint get_table_structure(const char *table, const char *db, char *table_t { fprintf(sql_file, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" - "/*!40101 SET character_set_client = utf8 */;\n" + "/*!40101 SET character_set_client = utf8mb4 */;\n" "%s%s;\n" "/*!40101 SET character_set_client = @saved_cs_client */;\n", is_log_table ? "CREATE TABLE IF NOT EXISTS " : "", diff --git a/mysql-test/include/ctype_supplementary_chars.inc b/mysql-test/include/ctype_supplementary_chars.inc new file mode 100644 index 00000000000..dfc2497125b --- /dev/null +++ b/mysql-test/include/ctype_supplementary_chars.inc @@ -0,0 +1,26 @@ +--eval CREATE TABLE t1 (a CHAR(8) DEFAULT REVERSE('aha')) $table_charset +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES (); +SELECT * FROM t1; + +--eval CREATE TABLE t2 (a CHAR(8) DEFAULT REVERSE('åäá')) $table_charset +SHOW CREATE TABLE t2; +INSERT INTO t2 VALUES (); +SELECT * FROM t2; + +--eval CREATE TABLE t3 (a CHAR(8) DEFAULT REVERSE('😎😀')) $table_charset +SHOW CREATE TABLE t3; +INSERT INTO t3 VALUES (); +SELECT * FROM t3; + +--eval CREATE TABLE t4 (a CHAR(8), b CHAR(8) AS (REVERSE('😎😀'))) $table_charset +SHOW CREATE TABLE t4; +INSERT INTO t4 (a) VALUES (''); +SELECT * FROM t4; + +--eval CREATE TABLE t5 (a CHAR(8), b CHAR(8) CHECK (b=BINARY REVERSE('😎😀'))) $table_charset +SHOW CREATE TABLE t5; +--error ER_CONSTRAINT_FAILED +INSERT INTO t5 VALUES ('','😎😀'); +INSERT INTO t5 VALUES ('','😀😎'); +SELECT * FROM t5; diff --git a/mysql-test/main/ctype_utf32.result b/mysql-test/main/ctype_utf32.result index 546a7415603..193ad73c7dc 100644 --- a/mysql-test/main/ctype_utf32.result +++ b/mysql-test/main/ctype_utf32.result @@ -3031,5 +3031,62 @@ SELECT CAST(CONVERT('-9223372036854775808' USING utf32) AS SIGNED) AS c1; c1 -9223372036854775808 # -# End of 10.5 tests +# MDEV-29968 Functions in default values in tables with some character sets break SHOW CREATE (and mysqldump) # +SET NAMES utf8mb4; +CREATE TABLE t1 (a CHAR(8) DEFAULT REVERSE('aha')) CHARACTER SET utf32; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(8) DEFAULT reverse('aha') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t1 VALUES (); +SELECT * FROM t1; +a +aha +CREATE TABLE t2 (a CHAR(8) DEFAULT REVERSE('åäá')) CHARACTER SET utf32; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` char(8) DEFAULT reverse('åäá') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t2 VALUES (); +SELECT * FROM t2; +a +áäå +CREATE TABLE t3 (a CHAR(8) DEFAULT REVERSE('😎😀')) CHARACTER SET utf32; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` char(8) DEFAULT reverse('😎😀') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t3 VALUES (); +SELECT * FROM t3; +a +😀😎 +CREATE TABLE t4 (a CHAR(8), b CHAR(8) AS (REVERSE('😎😀'))) CHARACTER SET utf32; +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `a` char(8) DEFAULT NULL, + `b` char(8) GENERATED ALWAYS AS (reverse('😎😀')) VIRTUAL +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t4 (a) VALUES (''); +SELECT * FROM t4; +a b + 😀😎 +CREATE TABLE t5 (a CHAR(8), b CHAR(8) CHECK (b=BINARY REVERSE('😎😀'))) CHARACTER SET utf32; +SHOW CREATE TABLE t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `a` char(8) DEFAULT NULL, + `b` char(8) DEFAULT NULL CHECK (`b` = cast(reverse('😎😀') as char charset binary)) +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t5 VALUES ('','😎😀'); +ERROR 23000: CONSTRAINT `t5.b` failed for `test`.`t5` +INSERT INTO t5 VALUES ('','😀😎'); +SELECT * FROM t5; +a b + 😀😎 +DROP TABLE t1, t2, t3, t4, t5; +# End of 10.5 tests diff --git a/mysql-test/main/ctype_utf32.test b/mysql-test/main/ctype_utf32.test index 4a1f27260c6..49e8b6f9bdb 100644 --- a/mysql-test/main/ctype_utf32.test +++ b/mysql-test/main/ctype_utf32.test @@ -1171,5 +1171,12 @@ SELECT HEX(DATE_FORMAT(TIME'11:22:33',@format)); SELECT CAST(CONVERT('-9223372036854775808' USING utf32) AS SIGNED) AS c1; --echo # ---echo # End of 10.5 tests +--echo # MDEV-29968 Functions in default values in tables with some character sets break SHOW CREATE (and mysqldump) --echo # + +SET NAMES utf8mb4; +--let $table_charset=CHARACTER SET utf32 +--source include/ctype_supplementary_chars.inc +DROP TABLE t1, t2, t3, t4, t5; + +--echo # End of 10.5 tests diff --git a/mysql-test/main/ctype_utf32_not_embedded.result b/mysql-test/main/ctype_utf32_not_embedded.result new file mode 100644 index 00000000000..55840fb4893 --- /dev/null +++ b/mysql-test/main/ctype_utf32_not_embedded.result @@ -0,0 +1,106 @@ +# Start of 10.5 tests +# +# MDEV-29968 Functions in default values in tables with some character sets break SHOW CREATE (and mysqldump) +# +SET NAMES utf8mb4; +CREATE TABLE t1 (a CHAR(8) DEFAULT REVERSE('aha')) CHARACTER SET utf32; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(8) DEFAULT reverse('aha') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t1 VALUES (); +SELECT * FROM t1; +a +aha +CREATE TABLE t2 (a CHAR(8) DEFAULT REVERSE('åäá')) CHARACTER SET utf32; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` char(8) DEFAULT reverse('åäá') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t2 VALUES (); +SELECT * FROM t2; +a +áäå +CREATE TABLE t3 (a CHAR(8) DEFAULT REVERSE('😎😀')) CHARACTER SET utf32; +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` char(8) DEFAULT reverse('😎😀') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t3 VALUES (); +SELECT * FROM t3; +a +😀😎 +CREATE TABLE t4 (a CHAR(8), b CHAR(8) AS (REVERSE('😎😀'))) CHARACTER SET utf32; +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `a` char(8) DEFAULT NULL, + `b` char(8) GENERATED ALWAYS AS (reverse('😎😀')) VIRTUAL +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t4 (a) VALUES (''); +SELECT * FROM t4; +a b + 😀😎 +CREATE TABLE t5 (a CHAR(8), b CHAR(8) CHECK (b=BINARY REVERSE('😎😀'))) CHARACTER SET utf32; +SHOW CREATE TABLE t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `a` char(8) DEFAULT NULL, + `b` char(8) DEFAULT NULL CHECK (`b` = cast(reverse('😎😀') as char charset binary)) +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +INSERT INTO t5 VALUES ('','😎😀'); +ERROR 23000: CONSTRAINT `t5.b` failed for `test`.`t5` +INSERT INTO t5 VALUES ('','😀😎'); +SELECT * FROM t5; +a b + 😀😎 +# Running dump +DROP TABLE t1, t2, t3, t4, t5; +# Running restore +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(8) DEFAULT reverse('aha') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +SELECT * FROM t1; +a +aha +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` char(8) DEFAULT reverse('åäá') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +SELECT * FROM t2; +a +áäå +SHOW CREATE TABLE t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `a` char(8) DEFAULT reverse('😎😀') +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +SELECT * FROM t3; +a +😀😎 +SHOW CREATE TABLE t4; +Table Create Table +t4 CREATE TABLE `t4` ( + `a` char(8) DEFAULT NULL, + `b` char(8) GENERATED ALWAYS AS (reverse('😎😀')) VIRTUAL +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +SELECT * FROM t4; +a b + 😀😎 +SHOW CREATE TABLE t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `a` char(8) DEFAULT NULL, + `b` char(8) DEFAULT NULL CHECK (`b` = cast(reverse('😎😀') as char charset binary)) +) ENGINE=MyISAM DEFAULT CHARSET=utf32 COLLATE=utf32_general_ci +SELECT * FROM t5; +a b + 😀😎 +DROP TABLE t1, t2, t3, t4, t5; +# End of 10.5 tests diff --git a/mysql-test/main/ctype_utf32_not_embedded.test b/mysql-test/main/ctype_utf32_not_embedded.test new file mode 100644 index 00000000000..622ba074078 --- /dev/null +++ b/mysql-test/main/ctype_utf32_not_embedded.test @@ -0,0 +1,38 @@ +# Embedded server doesn't support external clients +--source include/not_embedded.inc + +--echo # Start of 10.5 tests + +--echo # +--echo # MDEV-29968 Functions in default values in tables with some character sets break SHOW CREATE (and mysqldump) +--echo # + +SET NAMES utf8mb4; +--let $table_charset=CHARACTER SET utf32 +--source include/ctype_supplementary_chars.inc + +--echo # Running dump +--let $mysqldumpfile = $MYSQLTEST_VARDIR/tmp/ctype_utf32_not_embedded_dump.sql +--exec $MYSQL_DUMP test > $mysqldumpfile + +DROP TABLE t1, t2, t3, t4, t5; + +--echo # Running restore +--exec $MYSQL test < $mysqldumpfile +SHOW CREATE TABLE t1; +SELECT * FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2; +SHOW CREATE TABLE t3; +SELECT * FROM t3; +SHOW CREATE TABLE t4; +SELECT * FROM t4; +SHOW CREATE TABLE t5; +SELECT * FROM t5; + +DROP TABLE t1, t2, t3, t4, t5; + +--error 0,1 +--remove_file $mysqldumpfile + +--echo # End of 10.5 tests diff --git a/mysql-test/main/ddl_i18n_koi8r.result b/mysql-test/main/ddl_i18n_koi8r.result index be375e501cd..fa489aa9c15 100644 --- a/mysql-test/main/ddl_i18n_koi8r.result +++ b/mysql-test/main/ddl_i18n_koi8r.result @@ -1731,13 +1731,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER USE `mysqltest1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `log` ( `msg` varchar(255) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; @@ -1811,13 +1811,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER USE `mysqltest2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `log` ( `msg` varchar(255) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/mysql-test/main/ddl_i18n_utf8.result b/mysql-test/main/ddl_i18n_utf8.result index ef1b7e62d40..3cec11850ca 100644 --- a/mysql-test/main/ddl_i18n_utf8.result +++ b/mysql-test/main/ddl_i18n_utf8.result @@ -1731,13 +1731,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER USE `mysqltest1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `log` ( `msg` varchar(255) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; @@ -1811,13 +1811,13 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER USE `mysqltest2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `log` ( `msg` varchar(255) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/mysql-test/main/lock_view.result b/mysql-test/main/lock_view.result index cd693032d87..004536d60f7 100644 --- a/mysql-test/main/lock_view.result +++ b/mysql-test/main/lock_view.result @@ -22,7 +22,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER USE `mysqltest1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -32,7 +32,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest2` /*!40100 DEFAULT CHARACTER USE `mysqltest2`; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; @@ -41,27 +41,27 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest3` /*!40100 DEFAULT CHARACTER USE `mysqltest3`; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3i` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3is` AS SELECT 1 AS `schema_name` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3nt` AS SELECT 1 AS `1` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3ps` AS SELECT 1 AS `user` */; SET character_set_client = @saved_cs_client; @@ -238,7 +238,7 @@ disconnect con1; connection default; /*M!999999\- enable the sandbox mode */ SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `id` */; SET character_set_client = @saved_cs_client; diff --git a/mysql-test/main/mysql.result b/mysql-test/main/mysql.result index 1e02cd9f595..42620265567 100644 --- a/mysql-test/main/mysql.result +++ b/mysql-test/main/mysql.result @@ -562,7 +562,7 @@ a1\`b1 CREATE TABLE `a1\``b1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `a1\``b1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -592,7 +592,7 @@ a1\"b1 CREATE TABLE "a1\""b1" ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "a1\""b1" ( "a" int(11) DEFAULT NULL ); diff --git a/mysql-test/main/mysqldump-max.result b/mysql-test/main/mysqldump-max.result index 4a2fe09d44d..735fe6374bd 100644 --- a/mysql-test/main/mysqldump-max.result +++ b/mysql-test/main/mysqldump-max.result @@ -95,7 +95,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -107,7 +107,7 @@ INSERT DELAYED IGNORE INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'f /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -119,7 +119,7 @@ INSERT DELAYED IGNORE INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'f /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `t3`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -131,7 +131,7 @@ INSERT DELAYED IGNORE INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'f /*!40000 ALTER TABLE `t3` ENABLE KEYS */; DROP TABLE IF EXISTS `t4`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t4` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -143,7 +143,7 @@ INSERT DELAYED IGNORE INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'f /*!40000 ALTER TABLE `t4` ENABLE KEYS */; DROP TABLE IF EXISTS `t5`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t5` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -155,7 +155,7 @@ INSERT DELAYED IGNORE INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'f /*!40000 ALTER TABLE `t5` ENABLE KEYS */; DROP TABLE IF EXISTS `t6`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t6` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -193,7 +193,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -205,7 +205,7 @@ INSERT DELAYED INTO `t1` VALUES (1,'first value'),(2,'first value'),(3,'first va /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -217,7 +217,7 @@ INSERT DELAYED INTO `t2` VALUES (1,'first value'),(2,'first value'),(3,'first va /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `t3`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -229,7 +229,7 @@ INSERT DELAYED INTO `t3` VALUES (1,'first value'),(2,'first value'),(3,'first va /*!40000 ALTER TABLE `t3` ENABLE KEYS */; DROP TABLE IF EXISTS `t4`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t4` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -241,7 +241,7 @@ INSERT DELAYED INTO `t4` VALUES (1,'first value'),(2,'first value'),(3,'first va /*!40000 ALTER TABLE `t4` ENABLE KEYS */; DROP TABLE IF EXISTS `t5`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t5` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL @@ -253,7 +253,7 @@ INSERT DELAYED INTO `t5` VALUES (1,'first value'),(2,'first value'),(3,'first va /*!40000 ALTER TABLE `t5` ENABLE KEYS */; DROP TABLE IF EXISTS `t6`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t6` ( `id` int(8) DEFAULT NULL, `name` varchar(32) DEFAULT NULL diff --git a/mysql-test/main/mysqldump-nl.result b/mysql-test/main/mysqldump-nl.result index 56e9c56bae2..03dbc9ea13d 100644 --- a/mysql-test/main/mysqldump-nl.result +++ b/mysql-test/main/mysqldump-nl.result @@ -34,7 +34,7 @@ USE `mysqltest1 -- /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1 1t` ( `foobar @@ -53,7 +53,7 @@ raboof` int(11) DEFAULT NULL -- SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1 1v` AS SELECT 1 AS `foobar diff --git a/mysql-test/main/mysqldump-timing.result b/mysql-test/main/mysqldump-timing.result index 2ac132412f9..8afb8de6b8c 100644 --- a/mysql-test/main/mysqldump-timing.result +++ b/mysql-test/main/mysqldump-timing.result @@ -21,7 +21,7 @@ timeout without t1 contents expected /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `i` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -45,7 +45,7 @@ This would be a race condition otherwise, but default max_statement_time=0 makes /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `i` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; diff --git a/mysql-test/main/mysqldump-utf8mb4.result b/mysql-test/main/mysqldump-utf8mb4.result index dc2ec06554e..b1a5338c083 100644 --- a/mysql-test/main/mysqldump-utf8mb4.result +++ b/mysql-test/main/mysqldump-utf8mb4.result @@ -46,7 +46,7 @@ Testing text format output /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `point` varchar(10) NOT NULL, `data` varchar(10) DEFAULT NULL, diff --git a/mysql-test/main/mysqldump.result b/mysql-test/main/mysqldump.result index 08725299a38..93e0f9ee89c 100644 --- a/mysql-test/main/mysqldump.result +++ b/mysql-test/main/mysqldump.result @@ -33,7 +33,7 @@ INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` decimal(64,20) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -49,7 +49,7 @@ Warnings: Warning 1264 Out of range value for column 'a' at row 1 /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` double DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -71,7 +71,7 @@ ERROR 42S22: Unknown column '1.2345' in 'field list' SET SQL_MODE=@OLD_SQL_MODE; /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` decimal(10,5) DEFAULT NULL, `b` float DEFAULT NULL @@ -80,7 +80,7 @@ CREATE TABLE `t1` ( INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` decimal(10,5) DEFAULT NULL, `b` float DEFAULT NULL @@ -101,7 +101,7 @@ INSERT INTO `t1` VALUES (1.23450,2.3456),(1.23450,2.3456),(1.23450,2.3456),(1.23 /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` decimal(10,5) DEFAULT NULL, `b` float DEFAULT NULL @@ -131,7 +131,7 @@ UNLOCK TABLES; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` decimal(10,5) DEFAULT NULL, `b` float DEFAULT NULL @@ -214,7 +214,7 @@ INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` varchar(255) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=koi8r COLLATE=koi8r_general_ci; @@ -297,7 +297,7 @@ DROP TABLE t1; create table ```a` (i int); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE ```a` ( `i` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -321,7 +321,7 @@ create table t1(a int); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -350,7 +350,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "t1" ( "a" int(11) DEFAULT NULL ); @@ -382,7 +382,7 @@ set global sql_mode='ANSI_QUOTES'; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -411,7 +411,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "t1" ( "a" int(11) DEFAULT NULL ); @@ -447,7 +447,7 @@ insert into t1 values (1),(2),(3); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -544,7 +544,7 @@ INSERT INTO t1 VALUES (_latin1 ' /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` char(10) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -666,7 +666,7 @@ INSERT INTO t2 VALUES (4),(5),(6); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -708,7 +708,7 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `b` blob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -750,7 +750,7 @@ INSERT INTO t1 VALUES (4),(5),(6); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -785,7 +785,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1155,7 +1155,7 @@ insert into t1 (F_8d3bba7425e7c98c50f52ca1b52d3735) values (1); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `F_c4ca4238a0b923820dcc509a6f75849b` int(11) DEFAULT NULL, `F_c81e728d9d4c2f636f067f89cc14862c` int(11) DEFAULT NULL, @@ -1531,7 +1531,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1576,14 +1576,14 @@ INSERT INTO t2 VALUES (1), (2); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1612,14 +1612,14 @@ CREATE TABLE `t2` ( /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1807,7 +1807,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(10) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1820,7 +1820,7 @@ INSERT INTO `t1` VALUES (NULL),(10),(20); UNLOCK TABLES; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `pk` int(11) NOT NULL AUTO_INCREMENT, `a` int(10) DEFAULT NULL, @@ -1926,21 +1926,21 @@ mariadb-dump: Couldn't find table: "non_existing" /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t3`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -1976,7 +1976,7 @@ mariadb-dump: Got error: 1064: "You have an error in your SQL syntax; check the /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2013,7 +2013,7 @@ insert into t1 values (0815, 4711, 2006); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1"; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "t1" ( "a b" int(11) NOT NULL, "c""d" int(11) NOT NULL, @@ -2048,7 +2048,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a b` int(11) NOT NULL, `c"d` int(11) NOT NULL, @@ -2103,7 +2103,7 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` varchar(30) DEFAULT NULL, KEY `a` (`a`(5)) @@ -2118,7 +2118,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; @@ -2198,7 +2198,7 @@ create view v1 as select * from t1; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2211,7 +2211,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; @@ -2269,7 +2269,7 @@ create view v2 as select * from t2 where a like 'a%' with check option; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` varchar(30) DEFAULT NULL, KEY `a` (`a`(5)) @@ -2284,7 +2284,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; @@ -2335,7 +2335,7 @@ INSERT INTO t1 VALUES ('\''); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` char(10) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2382,7 +2382,7 @@ select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, @@ -2398,7 +2398,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `a`, 1 AS `b`, @@ -2407,14 +2407,14 @@ SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a` */; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v3`; /*!50001 DROP VIEW IF EXISTS `v3`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3` AS SELECT 1 AS `a`, 1 AS `b`, @@ -2536,7 +2536,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` bigint(20) DEFAULT NULL @@ -2608,7 +2608,7 @@ DELIMITER ; /*!50003 SET collation_connection = @saved_col_connection */ ; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2666,7 +2666,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` bigint(20) DEFAULT NULL @@ -2680,7 +2680,7 @@ INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); UNLOCK TABLES; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2814,7 +2814,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -2966,7 +2966,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), UNIQUE KEY `d` (`d`) @@ -3004,7 +3004,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), UNIQUE KEY `d` (`d`) @@ -3058,7 +3058,7 @@ a2 /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS "t1 test"; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "t1 test" ( "a1" int(11) DEFAULT NULL ); @@ -3087,7 +3087,7 @@ DELIMITER ; /*!50003 SET collation_connection = @saved_col_connection */ ; DROP TABLE IF EXISTS "t2 test"; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE "t2 test" ( "a2" int(11) DEFAULT NULL ); @@ -3142,7 +3142,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` varchar(32) DEFAULT NULL, @@ -3158,7 +3158,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v0`; /*!50001 DROP VIEW IF EXISTS `v0`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v0` AS SELECT 1 AS `a`, 1 AS `b`, @@ -3167,7 +3167,7 @@ SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `a`, 1 AS `b`, @@ -3176,7 +3176,7 @@ SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a`, 1 AS `b`, @@ -3268,7 +3268,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -3328,7 +3328,7 @@ insert into t1 values ('',''); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` binary(1) DEFAULT NULL, `b` blob DEFAULT NULL @@ -3364,7 +3364,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` binary(1) DEFAULT NULL, `b` blob DEFAULT NULL @@ -3549,7 +3549,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CH USE `mysqldump_test_db`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -3563,7 +3563,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `id` */; SET character_set_client = @saved_cs_client; @@ -3610,7 +3610,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_tables` /*!40100 DEFAULT CHA USE `mysqldump_tables`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `basetable` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `tag` varchar(64) DEFAULT NULL, @@ -3622,7 +3622,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_views` /*!40100 DEFAULT CHAR USE `mysqldump_views`; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `nasishnasifu` AS SELECT 1 AS `id` */; SET character_set_client = @saved_cs_client; @@ -3758,7 +3758,7 @@ use test; /*M!999999\- enable the sandbox mode */ DROP TABLE IF EXISTS `TABLES`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TEMPORARY TABLE `TABLES` ( `TABLE_CATALOG` varchar(512) NOT NULL, `TABLE_SCHEMA` varchar(64) NOT NULL, @@ -3834,14 +3834,14 @@ CREATE TABLE t1 (a INT) ENGINE=merge UNION=(t2, t3); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci UNION=(`t2`,`t3`); /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `t2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -3853,7 +3853,7 @@ LOCK TABLES `t2` WRITE; UNLOCK TABLES; DROP TABLE IF EXISTS `t3`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -3946,7 +3946,7 @@ CREATE TABLE t1 (c1 INT, c2 LONGBLOB); INSERT INTO t1 SET c1=11, c2=REPEAT('q',509); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `c1` int(11) DEFAULT NULL, `c2` longblob DEFAULT NULL @@ -4034,7 +4034,7 @@ create view db42635.v2 (c) as select * from db42635.t1; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -4047,7 +4047,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `c` */; SET character_set_client = @saved_cs_client; @@ -4184,7 +4184,7 @@ INSERT INTO t1 VALUES (3,4), (4,5); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL @@ -4461,7 +4461,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CH USE `mysqldump_test_db`; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -4475,7 +4475,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `id` */; SET character_set_client = @saved_cs_client; @@ -4573,7 +4573,7 @@ create table test (a int); /*M!999999\- enable the sandbox mode */ DROP TABLE IF EXISTS `test`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `test` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -4795,7 +4795,7 @@ ALTER DATABASE `test-database` CHARACTER SET latin1 COLLATE latin1_swedish_ci; ALTER DATABASE `test-database` CHARACTER SET utf8 COLLATE utf8_unicode_ci ; /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `test` ( `c1` varchar(10) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; @@ -5286,7 +5286,7 @@ CREATE TABLE t1 (a INT); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ); @@ -5565,20 +5565,20 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `db1` /*!40100 DEFAULT CHARACTER SET ut USE `db1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `basetable` ( `id` smallint(6) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `basetable` VALUES (5),(6); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_name` ( `i3` smallint(6) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci INSERT_METHOD=LAST UNION=(`basetable`); /*!40101 SET character_set_client = @saved_cs_client */; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `nonunique_table_view_name` AS SELECT 1 AS `1` */; SET character_set_client = @saved_cs_client; @@ -5587,7 +5587,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `db2` /*!40100 DEFAULT CHARACTER SET ut USE `db2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_name` ( `i1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, UNIQUE KEY `i1` (`i1`) @@ -5595,7 +5595,7 @@ CREATE TABLE `nonunique_table_name` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `nonunique_table_name` VALUES (1),(2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_view_name` ( `i2` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; @@ -5624,7 +5624,7 @@ USE `db2`; /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_name` ( `i1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, UNIQUE KEY `i1` (`i1`) @@ -5632,7 +5632,7 @@ CREATE TABLE `nonunique_table_name` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `nonunique_table_name` VALUES (1),(2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_view_name` ( `i2` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; @@ -5647,7 +5647,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `db2` /*!40100 DEFAULT CHARACTER SET ut USE `db2`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_name` ( `i1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, UNIQUE KEY `i1` (`i1`) @@ -5655,7 +5655,7 @@ CREATE TABLE `nonunique_table_name` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT DELAYED INTO `nonunique_table_name` VALUES (1),(2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_view_name` ( `i2` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; @@ -5666,21 +5666,21 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `db1` /*!40100 DEFAULT CHARACTER SET ut USE `db1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `basetable` ( `id` smallint(6) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; INSERT DELAYED INTO `basetable` VALUES (5),(6); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `nonunique_table_name` ( `i3` smallint(6) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci INSERT_METHOD=LAST UNION=(`basetable`); /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `nonunique_table_name` VALUES (5),(6); SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `nonunique_table_view_name` AS SELECT 1 AS `1` */; SET character_set_client = @saved_cs_client; @@ -5827,7 +5827,7 @@ DROP TABLE t1; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `general_log` ( `event_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -5838,7 +5838,7 @@ CREATE TABLE IF NOT EXISTS `general_log` ( ) ENGINE=CSV DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='General log'; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `slow_log` ( `start_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -5857,7 +5857,7 @@ CREATE TABLE IF NOT EXISTS `slow_log` ( /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `innodb_index_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_index_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -5872,7 +5872,7 @@ CREATE TABLE `innodb_index_stats` ( /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `innodb_table_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_table_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -5884,7 +5884,7 @@ CREATE TABLE `innodb_table_stats` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `transaction_registry` ( `transaction_id` bigint(20) unsigned NOT NULL, `commit_id` bigint(20) unsigned NOT NULL, @@ -5923,7 +5923,7 @@ CREATE TABLE IF NOT EXISTS `transaction_registry` ( /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `general_log` ( `event_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -5934,7 +5934,7 @@ CREATE TABLE IF NOT EXISTS `general_log` ( ) ENGINE=CSV DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='General log'; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `slow_log` ( `start_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -5953,7 +5953,7 @@ CREATE TABLE IF NOT EXISTS `slow_log` ( /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `innodb_index_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_index_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -5973,7 +5973,7 @@ LOCK TABLES `innodb_index_stats` WRITE; UNLOCK TABLES; DROP TABLE IF EXISTS `innodb_table_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_table_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -5990,7 +5990,7 @@ LOCK TABLES `innodb_table_stats` WRITE; /*!40000 ALTER TABLE `innodb_table_stats` ENABLE KEYS */; UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `transaction_registry` ( `transaction_id` bigint(20) unsigned NOT NULL, `commit_id` bigint(20) unsigned NOT NULL, @@ -6029,7 +6029,7 @@ CREATE TABLE IF NOT EXISTS `transaction_registry` ( /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `general_log` ( `event_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -6040,7 +6040,7 @@ CREATE TABLE IF NOT EXISTS `general_log` ( ) ENGINE=CSV DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='General log'; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `slow_log` ( `start_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6), `user_host` mediumtext NOT NULL, @@ -6059,7 +6059,7 @@ CREATE TABLE IF NOT EXISTS `slow_log` ( /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `innodb_index_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_index_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -6079,7 +6079,7 @@ LOCK TABLES `innodb_index_stats` WRITE; UNLOCK TABLES; DROP TABLE IF EXISTS `innodb_table_stats`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `innodb_table_stats` ( `database_name` varchar(64) NOT NULL, `table_name` varchar(199) NOT NULL, @@ -6096,7 +6096,7 @@ LOCK TABLES `innodb_table_stats` WRITE; /*!40000 ALTER TABLE `innodb_table_stats` ENABLE KEYS */; UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE IF NOT EXISTS `transaction_registry` ( `transaction_id` bigint(20) unsigned NOT NULL, `commit_id` bigint(20) unsigned NOT NULL, @@ -6143,7 +6143,7 @@ CREATE TABLE t4(ËÏÌÏÎËÁ1 INT); insert into t4 values(1); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) INVISIBLE DEFAULT NULL @@ -6151,7 +6151,7 @@ CREATE TABLE `t1` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t1` (`a`, `b`) VALUES (1,NULL),(1,2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL @@ -6159,7 +6159,7 @@ CREATE TABLE `t2` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t2` VALUES (1,2),(1,2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `invisible` int(11) DEFAULT NULL, `a b c & $!@#$%^&*( )` int(11) INVISIBLE DEFAULT 4, @@ -6168,7 +6168,7 @@ CREATE TABLE `t3` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t3` (`invisible`, `a b c & $!@#$%^&*( )`, `ds=~!@ \# $% ^ & * ( ) _ - = +`) VALUES (1,4,5),(5,4,5),(2,4,5),(1,2,3); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t4` ( `ËÏÌÏÎËÁ1` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -6177,7 +6177,7 @@ INSERT INTO `t4` VALUES (1); #Check side effect on --complete insert /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) INVISIBLE DEFAULT NULL @@ -6185,7 +6185,7 @@ CREATE TABLE `t1` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t1` (`a`, `b`) VALUES (1,NULL),(1,2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL @@ -6193,7 +6193,7 @@ CREATE TABLE `t2` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t2` (`a`, `b`) VALUES (1,2),(1,2); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t3` ( `invisible` int(11) DEFAULT NULL, `a b c & $!@#$%^&*( )` int(11) INVISIBLE DEFAULT 4, @@ -6202,7 +6202,7 @@ CREATE TABLE `t3` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t3` (`invisible`, `a b c & $!@#$%^&*( )`, `ds=~!@ \# $% ^ & * ( ) _ - = +`) VALUES (1,4,5),(5,4,5),(2,4,5),(1,2,3); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t4` ( `ËÏÌÏÎËÁ1` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -6529,7 +6529,7 @@ update mysql.event set body ='select not_a_value' where db='test' and name='e1'; create table t1 (i int); /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `i` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -6583,7 +6583,7 @@ create table t1 (a int); /*M!999999\- enable the sandbox mode */ DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; diff --git a/mysql-test/main/openssl_1.result b/mysql-test/main/openssl_1.result index bfe79a9df85..b90dc76f401 100644 --- a/mysql-test/main/openssl_1.result +++ b/mysql-test/main/openssl_1.result @@ -91,7 +91,7 @@ INSERT INTO t1 VALUES (1), (2); /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ); @@ -126,7 +126,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ); @@ -161,7 +161,7 @@ UNLOCK TABLES; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; DROP TABLE IF EXISTS `t1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ); diff --git a/mysql-test/main/trigger_wl3253.result b/mysql-test/main/trigger_wl3253.result index 8d4de24d4e0..54cc51a0e58 100644 --- a/mysql-test/main/trigger_wl3253.result +++ b/mysql-test/main/trigger_wl3253.result @@ -312,7 +312,7 @@ CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2; CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3; /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; @@ -375,7 +375,7 @@ CREATE TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:= # Expected order of triggers in the dump is: tr0_bi, tr1_bi, tr1_1_bi, tr2_i. /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; diff --git a/mysql-test/suite/compat/oracle/r/mysqldump_restore_func_qualified.result b/mysql-test/suite/compat/oracle/r/mysqldump_restore_func_qualified.result index 26468bd2415..c772c2e1eae 100644 --- a/mysql-test/suite/compat/oracle/r/mysqldump_restore_func_qualified.result +++ b/mysql-test/suite/compat/oracle/r/mysqldump_restore_func_qualified.result @@ -26,7 +26,7 @@ LTRIM(now()) AS a0, LPAD(now(),10) AS b0; /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a0` varchar(64) NOT NULL DEFAULT ltrim(current_timestamp()), `a1` varchar(64) GENERATED ALWAYS AS (ltrim(`a0`)) STORED, @@ -35,7 +35,7 @@ CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a0` varchar(64) NOT NULL DEFAULT ltrim_oracle(current_timestamp()), `a1` varchar(64) GENERATED ALWAYS AS (ltrim_oracle(`a0`)) STORED, @@ -44,13 +44,13 @@ CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci; /*!40101 SET character_set_client = @saved_cs_client */; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `a0`, 1 AS `b0` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a0`, 1 AS `b0` */; diff --git a/mysql-test/suite/federated/federatedx.result b/mysql-test/suite/federated/federatedx.result index 1d757dceb93..7f815c1a61c 100644 --- a/mysql-test/suite/federated/federatedx.result +++ b/mysql-test/suite/federated/federatedx.result @@ -2245,7 +2245,7 @@ CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1'; # Dump table t1 using mysqldump tool /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `id` varchar(20) NOT NULL, PRIMARY KEY (`id`) diff --git a/mysql-test/suite/roles/definer.result b/mysql-test/suite/roles/definer.result index 98cf82fc39b..5939dcf2cec 100644 --- a/mysql-test/suite/roles/definer.result +++ b/mysql-test/suite/roles/definer.result @@ -280,32 +280,32 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET l USE `test`; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v1` AS SELECT 1 AS `a+b`, 1 AS `c` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v2` AS SELECT 1 AS `a+b`, 1 AS `c`, 1 AS `current_role()` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v3` AS SELECT 1 AS `a+b`, 1 AS `c` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v4` AS SELECT 1 AS `a+b`, 1 AS `c` */; SET character_set_client = @saved_cs_client; SET @saved_cs_client = @@character_set_client; -SET character_set_client = utf8; +SET character_set_client = utf8mb4; /*!50001 CREATE VIEW `v5` AS SELECT 1 AS `a+b`, 1 AS `c` */; @@ -315,7 +315,7 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqltest1` /*!40100 DEFAULT CHARACTER USE `mysqltest1`; /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, @@ -324,7 +324,7 @@ CREATE TABLE `t1` ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO `t1` VALUES (1,10,100),(2,20,200); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, diff --git a/mysql-test/suite/sql_sequence/mysqldump.result b/mysql-test/suite/sql_sequence/mysqldump.result index e56162a434c..69817b42ec9 100644 --- a/mysql-test/suite/sql_sequence/mysqldump.result +++ b/mysql-test/suite/sql_sequence/mysqldump.result @@ -9,7 +9,7 @@ DO SETVAL(`a1`, 1, 0); CREATE SEQUENCE `x1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; DO SETVAL(`x1`, 1, 0); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, KEY `a` (`a`) @@ -23,7 +23,7 @@ DO SETVAL(`a1`, 1, 0); CREATE SEQUENCE `x1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; DO SETVAL(`x1`, 1, 0); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, KEY `a` (`a`) @@ -37,7 +37,7 @@ DO SETVAL(`a1`, 1, 0); CREATE SEQUENCE `x1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB; DO SETVAL(`x1`, 1, 0); /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, KEY `a` (`a`) @@ -47,7 +47,7 @@ INSERT INTO `t1` VALUES (1),(2); # dump by tables only tables /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, KEY `a` (`a`) diff --git a/sql/item.cc b/sql/item.cc index e6e69629fe5..7143bced98b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3936,7 +3936,7 @@ void Item_string::print(String *str, enum_query_type query_type) } else { - str_value.print(str, system_charset_info); + str_value.print(str, &my_charset_utf8mb4_general_ci); } } else diff --git a/sql/sql_show.cc b/sql/sql_show.cc index dff2a9c73da..7f03debcffb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1289,7 +1289,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) { Protocol *protocol= thd->protocol; char buff[2048]; - String buffer(buff, sizeof(buff), system_charset_info); + String buffer(buff, sizeof(buff), &my_charset_utf8mb4_general_ci); List field_list; bool error= TRUE; DBUG_ENTER("mysqld_show_create"); @@ -1709,7 +1709,7 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value, def_value->length(0); if (has_default) { - StringBuffer str(field->charset()); + StringBuffer str(&my_charset_utf8mb4_general_ci); if (field->default_value) { field->default_value->print(&str); @@ -2236,11 +2236,11 @@ int show_create_table_ex(THD *thd, TABLE_LIST *table_list, { packet->append(STRING_WITH_LEN(" INVISIBLE")); } - def_value.set(def_value_buf, sizeof(def_value_buf), system_charset_info); + def_value.set(def_value_buf, sizeof(def_value_buf), &my_charset_utf8mb4_general_ci); if (get_field_default_value(thd, field, &def_value, 1)) { packet->append(STRING_WITH_LEN(" DEFAULT ")); - packet->append(def_value.ptr(), def_value.length(), system_charset_info); + packet->append(def_value.ptr(), def_value.length(), &my_charset_utf8mb4_general_ci); } if (field->vers_update_unversioned()) diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result index 6e61fe3f4d7..93f68f5aad9 100644 --- a/storage/connect/mysql-test/connect/r/mysql.result +++ b/storage/connect/mysql-test/connect/r/mysql.result @@ -231,7 +231,7 @@ a # Start of mysqldump ------ /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL'; From a69da0c31e97109bba099022acdd393f92fa127f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 23 Dec 2024 21:27:00 +0100 Subject: [PATCH 37/41] MDEV-19761 Before Trigger not processed for Not Null Columns if no explicit value and no DEFAULT it's incorrect to zero out table->triggers->extra_null_bitmap before a statement, because if insert uses an explicit field list and omits a field that has no default value, the field should get NULL implicitly. So extra_null_bitmap should have 1s for all fields that have no defaults * create extra_null_bitmap_init and initialize it as above * copy extra_null_bitmap_init to extra_null_bitmap for inserts * still zero out extra_null_bitmap for updates/deletes where all fields definitely have a value * make not_null_fields_have_null_values() to send ER_NO_DEFAULT_FOR_FIELD for fields with no default and no value, otherwise creation of a trigger with an empty body would change the error message --- .../main/trigger_no_defaults-11698.result | 2 +- .../main/trigger_no_defaults-11698.test | 2 +- mysql-test/main/trigger_null-8605.result | 25 +++++++++ mysql-test/main/trigger_null-8605.test | 25 +++++++++ sql/field.h | 2 +- sql/field_conv.cc | 8 +-- sql/sql_base.cc | 9 +++- sql/sql_delete.cc | 4 +- sql/sql_insert.cc | 26 ++-------- sql/sql_insert.h | 7 +++ sql/sql_load.cc | 9 ++-- sql/sql_trigger.cc | 9 +++- sql/sql_trigger.h | 18 ++++--- sql/sql_update.cc | 4 +- sql/table.cc | 51 ++++++++++--------- 15 files changed, 127 insertions(+), 74 deletions(-) diff --git a/mysql-test/main/trigger_no_defaults-11698.result b/mysql-test/main/trigger_no_defaults-11698.result index 8ce495eaf3a..443bf15bb63 100644 --- a/mysql-test/main/trigger_no_defaults-11698.result +++ b/mysql-test/main/trigger_no_defaults-11698.result @@ -15,10 +15,10 @@ insert t1 (b) values (10); insert t1 (b) values (20); ERROR HY000: Field 'a' doesn't have a default value insert t1 (b) values (30); +ERROR 23000: Column 'a' cannot be null select * from t1; a b 10 10 -0 30 drop table t1; set sql_mode=default; set sql_mode=''; diff --git a/mysql-test/main/trigger_no_defaults-11698.test b/mysql-test/main/trigger_no_defaults-11698.test index c10bec68314..86a7a436ad0 100644 --- a/mysql-test/main/trigger_no_defaults-11698.test +++ b/mysql-test/main/trigger_no_defaults-11698.test @@ -19,7 +19,7 @@ delimiter ;| insert t1 (b) values (10); --error ER_NO_DEFAULT_FOR_FIELD insert t1 (b) values (20); -# arguably the statement below should fail too +--error ER_BAD_NULL_ERROR insert t1 (b) values (30); select * from t1; drop table t1; diff --git a/mysql-test/main/trigger_null-8605.result b/mysql-test/main/trigger_null-8605.result index 10315988708..6480fbf9a7e 100644 --- a/mysql-test/main/trigger_null-8605.result +++ b/mysql-test/main/trigger_null-8605.result @@ -364,3 +364,28 @@ create trigger tr before update on t1 for each row set @a = 1; insert into t1 (pk, i) values (null, null); ERROR 23000: Column 'pk' cannot be null drop table t1; +# +# MDEV-19761 Before Trigger not processed for Not Null Columns if no explicit value and no DEFAULT +# +create table t1( id int, rate int not null); +create trigger test_trigger before insert on t1 for each row +set new.rate=if(new.rate is null,10,new.rate); +insert into t1 (id) values (1); +insert into t1 values (2,3); +select * from t1; +id rate +1 10 +2 3 +create or replace trigger test_trigger before insert on t1 for each row +if new.rate is null then set new.rate = 15; end if; +$$ +insert into t1 (id) values (3); +insert into t1 values (4,5); +select * from t1; +id rate +1 10 +2 3 +3 15 +4 5 +drop table t1; +# End of 10.5 tests diff --git a/mysql-test/main/trigger_null-8605.test b/mysql-test/main/trigger_null-8605.test index 7645b61f5ad..e33f17151bf 100644 --- a/mysql-test/main/trigger_null-8605.test +++ b/mysql-test/main/trigger_null-8605.test @@ -391,3 +391,28 @@ create trigger tr before update on t1 for each row set @a = 1; --error ER_BAD_NULL_ERROR insert into t1 (pk, i) values (null, null); drop table t1; + +--echo # +--echo # MDEV-19761 Before Trigger not processed for Not Null Columns if no explicit value and no DEFAULT +--echo # +create table t1( id int, rate int not null); +create trigger test_trigger before insert on t1 for each row + set new.rate=if(new.rate is null,10,new.rate); + +insert into t1 (id) values (1); +insert into t1 values (2,3); +select * from t1; + +delimiter $$; +create or replace trigger test_trigger before insert on t1 for each row + if new.rate is null then set new.rate = 15; end if; +$$ +delimiter ;$$ + +insert into t1 (id) values (3); +insert into t1 values (4,5); +select * from t1; + +drop table t1; + +--echo # End of 10.5 tests diff --git a/sql/field.h b/sql/field.h index 3894c22e6da..09b9f895273 100644 --- a/sql/field.h +++ b/sql/field.h @@ -5846,7 +5846,7 @@ uint pack_length_to_packflag(uint type); enum_field_types get_blob_type_from_length(ulong length); int set_field_to_null(Field *field); int set_field_to_null_with_conversions(Field *field, bool no_conversions); -int convert_null_to_field_value_or_error(Field *field); +int convert_null_to_field_value_or_error(Field *field, uint err); bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name, enum_vcol_info_type type, Alter_info *alter_info= NULL); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 92e7551c00b..dcbb6b39a31 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -126,7 +126,7 @@ static int set_bad_null_error(Field *field, int err) return 0; case CHECK_FIELD_ERROR_FOR_NULL: if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name.str); + my_error(err, MYF(0), field->field_name.str); return -1; } DBUG_ASSERT(0); // impossible @@ -164,7 +164,7 @@ int set_field_to_null(Field *field) If no_conversion was not set, an error message is printed */ -int convert_null_to_field_value_or_error(Field *field) +int convert_null_to_field_value_or_error(Field *field, uint err) { if (field->type() == MYSQL_TYPE_TIMESTAMP) { @@ -179,7 +179,7 @@ int convert_null_to_field_value_or_error(Field *field) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - return set_bad_null_error(field, ER_BAD_NULL_ERROR); + return set_bad_null_error(field, err); } /** @@ -216,7 +216,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) if (no_conversions) return -1; - return convert_null_to_field_value_or_error(field); + return convert_null_to_field_value_or_error(field, ER_BAD_NULL_ERROR); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index aaa86e7bfa0..bb73dcef975 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8622,7 +8622,6 @@ void switch_to_nullable_trigger_fields(List &items, TABLE *table) while ((item= it++)) item->walk(&Item::switch_to_nullable_fields_processor, 1, field); - table->triggers->reset_extra_null_bitmap(); } } @@ -8676,8 +8675,14 @@ static bool not_null_fields_have_null_values(TABLE *table) swap_variables(uint32, of->flags, ff->flags); if (ff->is_real_null()) { + uint err= ER_BAD_NULL_ERROR; + if (ff->flags & NO_DEFAULT_VALUE_FLAG && !ff->has_explicit_value()) + { + err= ER_NO_DEFAULT_FOR_FIELD; + table->in_use->count_cuted_fields= CHECK_FIELD_WARN; + } ff->set_notnull(); // for next row WHERE condition in UPDATE - if (convert_null_to_field_value_or_error(of) || thd->is_error()) + if (convert_null_to_field_value_or_error(of, err) || thd->is_error()) return true; } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index fa677feb551..d85a04aa9bb 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -722,8 +722,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->mark_columns_needed_for_delete(); } - if ((table->file->ha_table_flags() & HA_CAN_FORCE_BULK_DELETE) && - !table->prepare_triggers_for_delete_stmt_or_event()) + if (!table->prepare_triggers_for_delete_stmt_or_event() && + table->file->ha_table_flags() & HA_CAN_FORCE_BULK_DELETE) will_batch= !table->file->start_bulk_delete(); /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index acc841e27f0..2a978640122 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1019,7 +1019,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, INSERT INTO t1 (fields) VALUES ... INSERT INTO t1 VALUES () */ - restore_record(table,s->default_values); // Get empty record + restore_default_record_for_insert(table); table->reset_default_fields(); if (unlikely(fill_record_n_invoke_before_triggers(thd, table, fields, @@ -1048,7 +1048,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, */ if (thd->lex->used_tables || // Column used in values() table->s->visible_fields != table->s->fields) - restore_record(table,s->default_values); // Get empty record + restore_default_record_for_insert(table); else { TABLE_SHARE *share= table->s; @@ -1085,24 +1085,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, } } - /* - with triggers a field can get a value *conditionally*, so we have to - repeat has_no_default_value() check for every row - */ - if (table->triggers && - table->triggers->has_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE)) - { - for (Field **f=table->field ; *f ; f++) - { - if (unlikely(!(*f)->has_explicit_value() && - has_no_default_value(thd, *f, table_list))) - { - error= 1; - goto values_loop_end; - } - } - } - if ((res= table_list->view_check_option(thd, (values_list.elements == 1 ? 0 : @@ -4081,7 +4063,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) */ table->file->ha_start_bulk_insert((ha_rows) 0); } - restore_record(table,s->default_values); // Get empty record + restore_default_record_for_insert(table); table->reset_default_fields(); table->next_number_field=table->found_next_number_field; @@ -4226,7 +4208,7 @@ int select_insert::send_data(List &values) originally touched by INSERT ... SELECT, so we have to restore their original values for the next row. */ - restore_record(table, s->default_values); + restore_default_record_for_insert(table); } if (table->next_number_field) { diff --git a/sql/sql_insert.h b/sql/sql_insert.h index 80666a81c50..9aa234b715e 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -46,6 +46,13 @@ void kill_delayed_threads(void); bool binlog_create_table(THD *thd, TABLE *table, bool replace); bool binlog_drop_table(THD *thd, TABLE *table); +static inline void restore_default_record_for_insert(TABLE *t) +{ + restore_record(t,s->default_values); + if (t->triggers) + t->triggers->default_extra_null_bitmap(); +} + #ifdef EMBEDDED_LIBRARY inline void kill_delayed_threads(void) {} #endif diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 3ccb6f48994..778ee498e41 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -23,7 +23,6 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_load.h" -#include "sql_load.h" #include "sql_cache.h" // query_cache_* #include "sql_base.h" // fill_record_n_invoke_before_triggers #include @@ -1004,8 +1003,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, read_info.row_end[0]=0; #endif - restore_record(table, s->default_values); - + restore_default_record_for_insert(table); while ((item= it++)) { Load_data_outvar *dst= item->get_load_data_outvar(); @@ -1118,8 +1116,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, thd->progress.max_counter); } } - restore_record(table, s->default_values); + restore_default_record_for_insert(table); while ((item= it++)) { uint length; @@ -1273,8 +1271,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } #endif - restore_record(table, s->default_values); - + restore_default_record_for_insert(table); while ((item= it++)) { /* If this line is to be skipped we don't want to fill field or var */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index f35a07347fe..f85faff37ac 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1297,8 +1297,9 @@ bool Table_triggers_list::prepare_record_accessors(TABLE *table) { int null_bytes= (table->s->fields - table->s->null_fields + 7)/8; - if (!(extra_null_bitmap= (uchar*)alloc_root(&table->mem_root, null_bytes))) + if (!(extra_null_bitmap= (uchar*)alloc_root(&table->mem_root, 2*null_bytes))) return 1; + extra_null_bitmap_init= extra_null_bitmap + null_bytes; if (!(record0_field= (Field **)alloc_root(&table->mem_root, (table->s->fields + 1) * sizeof(Field*)))) @@ -1323,13 +1324,17 @@ bool Table_triggers_list::prepare_record_accessors(TABLE *table) null_ptr++, null_bit= 1; else null_bit*= 2; + if (f->flags & NO_DEFAULT_VALUE_FLAG) + f->set_null(); + else + f->set_notnull(); } else *trg_fld= *fld; } *trg_fld= 0; DBUG_ASSERT(null_ptr <= extra_null_bitmap + null_bytes); - bzero(extra_null_bitmap, null_bytes); + memcpy(extra_null_bitmap_init, extra_null_bitmap, null_bytes); } else { diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 101784ee776..685f4d15b3b 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -147,7 +147,7 @@ class Table_triggers_list: public Sql_alloc BEFORE INSERT/UPDATE triggers. */ Field **record0_field; - uchar *extra_null_bitmap; + uchar *extra_null_bitmap, *extra_null_bitmap_init; /** Copy of TABLE::Field array with field pointers set to TABLE::record[1] buffer instead of TABLE::record[0] (used for OLD values in on UPDATE @@ -211,8 +211,8 @@ public: /* End of character ser context. */ Table_triggers_list(TABLE *table_arg) - :record0_field(0), extra_null_bitmap(0), record1_field(0), - trigger_table(table_arg), + :record0_field(0), extra_null_bitmap(0), extra_null_bitmap_init(0), + record1_field(0), trigger_table(table_arg), m_has_unparseable_trigger(false), count(0) { bzero((char *) triggers, sizeof(triggers)); @@ -276,11 +276,15 @@ public: TABLE_LIST *table_list); Field **nullable_fields() { return record0_field; } - void reset_extra_null_bitmap() + void clear_extra_null_bitmap() { - size_t null_bytes= (trigger_table->s->fields - - trigger_table->s->null_fields + 7)/8; - bzero(extra_null_bitmap, null_bytes); + if (size_t null_bytes= extra_null_bitmap_init - extra_null_bitmap) + bzero(extra_null_bitmap, null_bytes); + } + void default_extra_null_bitmap() + { + if (size_t null_bytes= extra_null_bitmap_init - extra_null_bitmap) + memcpy(extra_null_bitmap, extra_null_bitmap_init, null_bytes); } Trigger *find_trigger(const LEX_CSTRING *name, bool remove_from_list); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 9dfb681b119..f2cea510ce7 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -996,8 +996,8 @@ update_begin: goto update_end; } - if ((table->file->ha_table_flags() & HA_CAN_FORCE_BULK_UPDATE) && - !table->prepare_triggers_for_update_stmt_or_event()) + if (!table->prepare_triggers_for_update_stmt_or_event() && + table->file->ha_table_flags() & HA_CAN_FORCE_BULK_UPDATE) will_batch= !table->file->start_bulk_update(); /* diff --git a/sql/table.cc b/sql/table.cc index b18ee64f480..0aad7ae24e1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9140,8 +9140,8 @@ void TABLE::prepare_triggers_for_insert_stmt_or_event() { if (triggers) { - if (triggers->has_triggers(TRG_EVENT_DELETE, - TRG_ACTION_AFTER)) + triggers->clear_extra_null_bitmap(); + if (triggers->has_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER)) { /* The table has AFTER DELETE triggers that might access to @@ -9150,8 +9150,7 @@ void TABLE::prepare_triggers_for_insert_stmt_or_event() */ (void) file->extra(HA_EXTRA_DELETE_CANNOT_BATCH); } - if (triggers->has_triggers(TRG_EVENT_UPDATE, - TRG_ACTION_AFTER)) + if (triggers->has_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER)) { /* The table has AFTER UPDATE triggers that might access to subject @@ -9166,17 +9165,19 @@ void TABLE::prepare_triggers_for_insert_stmt_or_event() bool TABLE::prepare_triggers_for_delete_stmt_or_event() { - if (triggers && - triggers->has_triggers(TRG_EVENT_DELETE, - TRG_ACTION_AFTER)) + if (triggers) { - /* - The table has AFTER DELETE triggers that might access to subject table - and therefore might need delete to be done immediately. So we turn-off - the batching. - */ - (void) file->extra(HA_EXTRA_DELETE_CANNOT_BATCH); - return TRUE; + triggers->clear_extra_null_bitmap(); + if (triggers->has_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER)) + { + /* + The table has AFTER DELETE triggers that might access to subject table + and therefore might need delete to be done immediately. So we turn-off + the batching. + */ + (void) file->extra(HA_EXTRA_DELETE_CANNOT_BATCH); + return TRUE; + } } return FALSE; } @@ -9184,17 +9185,19 @@ bool TABLE::prepare_triggers_for_delete_stmt_or_event() bool TABLE::prepare_triggers_for_update_stmt_or_event() { - if (triggers && - triggers->has_triggers(TRG_EVENT_UPDATE, - TRG_ACTION_AFTER)) + if (triggers) { - /* - The table has AFTER UPDATE triggers that might access to subject - table and therefore might need update to be done immediately. - So we turn-off the batching. - */ - (void) file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH); - return TRUE; + triggers->clear_extra_null_bitmap(); + if (triggers->has_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER)) + { + /* + The table has AFTER UPDATE triggers that might access to subject + table and therefore might need update to be done immediately. + So we turn-off the batching. + */ + (void) file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH); + return TRUE; + } } return FALSE; } From b87c1b06dceaa8f7db7fc900931829aef4421713 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Jan 2025 08:10:49 +0100 Subject: [PATCH 38/41] MDEV-29968 update test results followup for 350cc77fee66 --- mysql-test/suite/s3/mysqldump.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/s3/mysqldump.result b/mysql-test/suite/s3/mysqldump.result index 78d97874c87..47adac57e23 100644 --- a/mysql-test/suite/s3/mysqldump.result +++ b/mysql-test/suite/s3/mysqldump.result @@ -18,7 +18,7 @@ alter table t1 engine=S3; ### /*M!999999\- enable the sandbox mode */ /*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; +/*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `t1` ( `pk` int(11) NOT NULL, `a` int(11) DEFAULT NULL, From b1f57a98a8fe1d79e3d1b827501383a19301d6fa Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Jan 2025 15:07:53 +0100 Subject: [PATCH 39/41] cleanup: Alter_table_ctx::Alter_table_ctx() --- sql/sql_alter.cc | 22 ++++------------------ sql/sql_alter.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index dc98f9c8d93..d8cb7e8f341 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -297,16 +297,8 @@ uint Alter_info::check_vcol_field(Item_field *item) const Alter_table_ctx::Alter_table_ctx() - : implicit_default_value_error_field(NULL), - error_if_not_empty(false), - tables_opened(0), - db(null_clex_str), table_name(null_clex_str), alias(null_clex_str), - new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str), - fk_error_if_delete_row(false), fk_error_id(NULL), - fk_error_table(NULL), modified_primary_key(false) -#ifdef DBUG_ASSERT_EXISTS - , tmp_table(false) -#endif + : db(null_clex_str), table_name(null_clex_str), alias(null_clex_str), + new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str) { } @@ -319,14 +311,8 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list, uint tables_opened_arg, const LEX_CSTRING *new_db_arg, const LEX_CSTRING *new_name_arg) - : implicit_default_value_error_field(NULL), error_if_not_empty(false), - tables_opened(tables_opened_arg), - new_db(*new_db_arg), new_name(*new_name_arg), - fk_error_if_delete_row(false), fk_error_id(NULL), - fk_error_table(NULL), modified_primary_key(false) -#ifdef DBUG_ASSERT_EXISTS - , tmp_table(false) -#endif + : tables_opened(tables_opened_arg), + new_db(*new_db_arg), new_name(*new_name_arg) { /* Assign members db, table_name, new_db and new_name diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 65643eac46f..c5e6cb9ba34 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -306,9 +306,9 @@ public: void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const; public: - Create_field *implicit_default_value_error_field; - bool error_if_not_empty; - uint tables_opened; + Create_field *implicit_default_value_error_field= NULL; + bool error_if_not_empty= false; + uint tables_opened= 0; LEX_CSTRING db; LEX_CSTRING table_name; LEX_CSTRING alias; @@ -322,12 +322,12 @@ public: of table to the new version ER_FK_CANNOT_DELETE_PARENT error should be emitted. */ - bool fk_error_if_delete_row; + bool fk_error_if_delete_row= false; /** Name of foreign key for the above error. */ - const char *fk_error_id; + const char *fk_error_id= NULL; /** Name of table for the above error. */ - const char *fk_error_table; - bool modified_primary_key; + const char *fk_error_table= NULL; + bool modified_primary_key= false; private: char new_filename[FN_REFLEN + 1]; @@ -339,7 +339,7 @@ private: #ifdef DBUG_ASSERT_EXISTS /** Indicates that we are altering temporary table. Used only in asserts. */ - bool tmp_table; + bool tmp_table= false; #endif Alter_table_ctx &operator=(const Alter_table_ctx &rhs); // not implemented From 782c4b94f08ef50f5f86e70c14a601e20ca72f1a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 18 Jan 2025 15:11:12 +0100 Subject: [PATCH 40/41] MDEV-25654 only force HA_KEY_ALG_HASH for fast alter partition not for any ALTER TABLE without ALTER_CHANGE_COLUMN. This fixes galera_sr.MDEV-28971 test followup for 0dcd30197ade --- mysql-test/main/long_unique_bugs.result | 6 ++++++ mysql-test/main/long_unique_bugs.test | 5 +++++ sql/sql_alter.h | 1 + sql/sql_table.cc | 25 +++++++++---------------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result index 1caec209d9f..5ee8b65fbf6 100644 --- a/mysql-test/main/long_unique_bugs.result +++ b/mysql-test/main/long_unique_bugs.result @@ -741,4 +741,10 @@ insert into t1 select seq from seq_1_to_100; alter table t1 add partition (partition p3 values less than (maxvalue)); alter table t1 force; drop table t1; +# veirfy that duplicate has unique is detected +create table t1 (a blob unique); +alter table t1 add constraint constraint_1 unique (a); +Warnings: +Note 1831 Duplicate index `constraint_1`. This is deprecated and will be disallowed in a future release +drop table t1; # End of 10.5 tests diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index 6ad59fe6495..3fbe2a6b777 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -721,4 +721,9 @@ alter table t1 force; drop table t1; +--echo # veirfy that duplicate has unique is detected +create table t1 (a blob unique); +alter table t1 add constraint constraint_1 unique (a); +drop table t1; + --echo # End of 10.5 tests diff --git a/sql/sql_alter.h b/sql/sql_alter.h index c5e6cb9ba34..5e7f59650b2 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -328,6 +328,7 @@ public: /** Name of table for the above error. */ const char *fk_error_table= NULL; bool modified_primary_key= false; + bool fast_alter_partition= false; private: char new_filename[FN_REFLEN + 1]; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3563c0fa982..aec81d8941e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9276,19 +9276,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, LEX_CSTRING tmp_name; bzero((char*) &key_create_info, sizeof(key_create_info)); if (key_info->algorithm == HA_KEY_ALG_LONG_HASH) - key_info->algorithm= (alter_info->flags & ALTER_CHANGE_COLUMN) ? - HA_KEY_ALG_UNDEF : HA_KEY_ALG_HASH; + key_info->algorithm= alter_ctx->fast_alter_partition ? + HA_KEY_ALG_HASH : HA_KEY_ALG_UNDEF; /* - This one goes to mysql_prepare_create_table(): - - key_info->algorithm= key->key_create_info.algorithm; - - For HA_KEY_ALG_LONG_HASH if we didn't change ANY column, we pass - HA_KEY_ALG_HASH to ensure mysql_prepare_create_table() does add_hash_field(). - This protects fast alter partition from losing hash properties. - In case of any column changes we drop algorithm to HA_KEY_ALG_UNDEF and - let decide mysql_prepare_create_table() if the hash field is needed - depending on new types. + For fast alter partition we set HA_KEY_ALG_HASH above to make sure it + doesn't lose the hash property. + Otherwise we let mysql_prepare_create_table() decide if the hash field + is needed depending on the (possibly changed) data types. */ key_create_info.algorithm= key_info->algorithm; /* @@ -10317,7 +10311,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db, TABLE *table, *new_table= nullptr; #ifdef WITH_PARTITION_STORAGE_ENGINE bool partition_changed= false; - bool fast_alter_partition= false; #endif /* Create .FRM for new version of table with a temporary name. @@ -10844,7 +10837,7 @@ do_continue:; Partitioning: part_info is prepared and returned via thd->work_part_info */ if (prep_alter_part_table(thd, table, alter_info, create_info, - &partition_changed, &fast_alter_partition)) + &partition_changed, &alter_ctx.fast_alter_partition)) { DBUG_RETURN(true); } @@ -10879,7 +10872,7 @@ do_continue:; Note, one can run a separate "ALTER TABLE t1 FORCE;" statement before or after the partition change ALTER statement to upgrade data types. */ - if (IF_PARTITIONING(!fast_alter_partition, 1)) + if (!alter_ctx.fast_alter_partition) Create_field::upgrade_data_types(alter_info->create_list); if (create_info->check_fields(thd, alter_info, @@ -10891,7 +10884,7 @@ do_continue:; promote_first_timestamp_column(&alter_info->create_list); #ifdef WITH_PARTITION_STORAGE_ENGINE - if (fast_alter_partition) + if (alter_ctx.fast_alter_partition) { /* ALGORITHM and LOCK clauses are generally not allowed by the From cbb24d9aa5978c1a2d008f9ebf208acd9ee9eaa9 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Thu, 16 Jan 2025 20:57:01 -0700 Subject: [PATCH 41/41] MDEV-35646: Limit `pseudo_thread_id` to `UINT32_MAX` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the `my_thread_id` type is 64 bits, binlog format specs limits it to 32 bits in practice. (See also: MDEV-35706) The writable SQL variable `pseudo_thread_id` didn’t realize this though and had a range of `ULONGLONG_MAX` (at least `UINT64_MAX` in C/C++). It consequentially accepted larger values silently, but only the lower 32 bits of whom gets binlogged; this could lead to inconsistency. Reviewed-by: Brandon Nesterenko --- include/my_pthread.h | 7 +++++++ mysql-test/suite/sys_vars/r/sysvars_server_embedded.result | 2 +- .../suite/sys_vars/r/sysvars_server_notembedded.result | 2 +- sql/mysqld.cc | 2 +- sql/sys_vars.cc | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/my_pthread.h b/include/my_pthread.h index 10cc2301ea6..519d1be1cb5 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -641,6 +641,13 @@ extern pthread_mutexattr_t my_errorcheck_mutexattr; #endif typedef uint64 my_thread_id; +/** + Long-standing formats (such as the client-server protocol and the binary log) + hard-coded `my_thread_id` to 32 bits in practice. (Though not all + `thread_id`s are typed as such, @ref my_thread_id itself among those.) + @see MDEV-35706 +*/ +#define MY_THREAD_ID_MAX UINT32_MAX extern void my_threadattr_global_init(void); extern my_bool my_thread_global_init(void); diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index a5a02bfa1bc..cdf6d210933 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2877,7 +2877,7 @@ VARIABLE_SCOPE SESSION ONLY VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT This variable is for internal server use NUMERIC_MIN_VALUE 0 -NUMERIC_MAX_VALUE 18446744073709551615 +NUMERIC_MAX_VALUE 4294967295 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 50dd4ae23a3..0af08d00c89 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -3037,7 +3037,7 @@ VARIABLE_SCOPE SESSION ONLY VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT This variable is for internal server use NUMERIC_MIN_VALUE 0 -NUMERIC_MAX_VALUE 18446744073709551615 +NUMERIC_MAX_VALUE 4294967295 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY NO diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d6dd8a566af..7a7c1f0491a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -9770,7 +9770,7 @@ void init_server_psi_keys(void) */ -static my_thread_id thread_id_max= UINT_MAX32; +static my_thread_id thread_id_max= MY_THREAD_ID_MAX; #include #include diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 93298ff7b04..a2058dee224 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1767,7 +1767,7 @@ Sys_pseudo_thread_id( "pseudo_thread_id", "This variable is for internal server use", SESSION_ONLY(pseudo_thread_id), - NO_CMD_LINE, VALID_RANGE(0, ULONGLONG_MAX), DEFAULT(0), + NO_CMD_LINE, VALID_RANGE(0, MY_THREAD_ID_MAX), DEFAULT(0), BLOCK_SIZE(1), NO_MUTEX_GUARD, IN_BINLOG); static bool