From 4a90bb85c0cb1407b0f112245e47ec995dc767c7 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Mon, 24 Aug 2020 20:53:51 +0300 Subject: [PATCH 1/9] InnoDB: fix debug assertion --- storage/innobase/row/row0upd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 63c1ea8d662..800c7a6d1f3 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2438,7 +2438,7 @@ row_upd_sec_index_entry( #ifdef UNIV_DEBUG mtr_commit(&mtr); mtr_start(&mtr); - ut_ad(btr_validate_index(index, 0, false)); + ut_ad(btr_validate_index(index, 0, false) == DB_SUCCESS); ut_ad(0); #endif /* UNIV_DEBUG */ break; From 6fa40b85be8cd35d337a4b4b7cf910a81518d298 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Aug 2020 10:15:04 +0300 Subject: [PATCH 2/9] MDEV-23554 Wrong default value for foreign_key_checks variable Sys_var_bit::session_save_default() ignored reverse_semantics property. --- mysql-test/suite/innodb/r/foreign_key.result | 1 - mysql-test/suite/innodb/t/foreign_key.test | 1 - .../suite/sys_vars/r/foreign_key_checks_basic.result | 2 +- mysql-test/suite/sys_vars/r/unique_checks_basic.result | 2 +- sql/sys_vars.ic | 7 +++++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index bab4ea16643..fb4175c0327 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -167,7 +167,6 @@ PRIMARY KEY (store_id), UNIQUE KEY idx_unique_manager (manager_staff_id), CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB; -SET FOREIGN_KEY_CHECKS=DEFAULT; LOCK TABLE staff WRITE; UNLOCK TABLES; DROP TABLES staff, store; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 40bc3a32a4f..e0d83338dc2 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -136,7 +136,6 @@ CREATE TABLE store ( UNIQUE KEY idx_unique_manager (manager_staff_id), CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB; -SET FOREIGN_KEY_CHECKS=DEFAULT; LOCK TABLE staff WRITE; UNLOCK TABLES; diff --git a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result index 834d693edb8..0bf9d859d40 100644 --- a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result @@ -7,7 +7,7 @@ SET @@session.foreign_key_checks = 1; SET @@session.foreign_key_checks = DEFAULT; SELECT @@session.foreign_key_checks; @@session.foreign_key_checks -0 +1 '#---------------------FN_DYNVARS_032_02-------------------------#' SET foreign_key_checks = 1; SELECT @@foreign_key_checks; diff --git a/mysql-test/suite/sys_vars/r/unique_checks_basic.result b/mysql-test/suite/sys_vars/r/unique_checks_basic.result index 60cf2795309..83fb9edb4cd 100644 --- a/mysql-test/suite/sys_vars/r/unique_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/unique_checks_basic.result @@ -7,7 +7,7 @@ SET @@session.unique_checks= 1; SET @@session.unique_checks= DEFAULT; SELECT @@session.unique_checks; @@session.unique_checks -0 +1 '#--------------------FN_DYNVARS_005_04-------------------------#' SET @@session.unique_checks =1; SELECT @@session.unique_checks; diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index a18440e550d..f547bd741fc 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -1704,13 +1704,16 @@ public: return false; } void session_save_default(THD *thd, set_var *var) - { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; } + { + var->save_result.ulonglong_value= + (reverse_semantics == !(global_var(ulonglong) & bitmask)); + } void global_save_default(THD *thd, set_var *var) { var->save_result.ulonglong_value= option.def_value; } uchar *valptr(THD *thd, ulonglong val) { - thd->sys_var_tmp.my_bool_value= reverse_semantics ^ ((val & bitmask) != 0); + thd->sys_var_tmp.my_bool_value= (reverse_semantics == !(val & bitmask)); return (uchar*) &thd->sys_var_tmp.my_bool_value; } uchar *session_value_ptr(THD *thd, const LEX_STRING *base) From 0be70a1b773ce66ef1803fcce19522fd9c60c07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 17 Aug 2020 08:57:13 +0300 Subject: [PATCH 3/9] MDEV-23483: Set Galera SST thd as system thread Revert change to MDL and set SST donor thread as a system thread. Joiner thread was already a system thread. --- mysql-test/suite/galera/t/mdev-22543.test | 20 +++++++++--------- sql/mdl.cc | 25 ++++++++--------------- sql/wsrep_sst.cc | 18 +++++----------- sql/wsrep_utils.cc | 4 +++- sql/wsrep_utils.h | 2 +- 5 files changed, 27 insertions(+), 42 deletions(-) diff --git a/mysql-test/suite/galera/t/mdev-22543.test b/mysql-test/suite/galera/t/mdev-22543.test index 53662e36942..1e7d3712639 100644 --- a/mysql-test/suite/galera/t/mdev-22543.test +++ b/mysql-test/suite/galera/t/mdev-22543.test @@ -5,15 +5,15 @@ --source include/galera_cluster.inc --source include/have_debug.inc --source include/have_debug_sync.inc - + --let $node_1 = node_1 --let $node_2 = node_2 --source include/auto_increment_offset_save.inc - + --let $galera_connection_name = node_1_ctrl --let $galera_server_number = 1 --source include/galera_connect.inc - + # # Run UPDATE on node_1 and make it block before table locks are taken. # This should block FTWRL. @@ -23,10 +23,10 @@ CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); INSERT INTO t1 VALUES (1, 1); SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; --send UPDATE t1 SET f2 = 2 WHERE f1 = 1 - + --connection node_1_ctrl SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; - + # # Restart node_2, force SST. # @@ -40,19 +40,19 @@ SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; # If the bug is present, FTWRL times out on node_1 in couple of # seconds and node_2 fails to join. --sleep 10 - + --connection node_1_ctrl SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; - + --connection node_1 --reap SET DEBUG_SYNC = "RESET"; - + --connection node_2 --enable_reconnect --source include/wait_until_connected_again.inc - + --connection node_1 DROP TABLE t1; - + --source include/auto_increment_offset_restore.inc diff --git a/sql/mdl.cc b/sql/mdl.cc index 14a1f17fe86..9eeb82eeffd 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -25,7 +25,6 @@ #include #include "wsrep_mysqld.h" #include "wsrep_thd.h" -#include "wsrep_sst.h" #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -2138,26 +2137,18 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE, mdl_request->key.get_wait_state_name()); - THD* thd= m_owner->get_thd(); - if (wait_status != MDL_wait::EMPTY) break; /* Check if the client is gone while we were waiting. */ - if (! thd_is_connected(thd)) + if (! thd_is_connected(m_owner->get_thd())) { -#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) - // During SST client might not be connected - if (!wsrep_is_sst_progress()) -#endif - { - /* - * The client is disconnected. Don't wait forever: - * assume it's the same as a wait timeout, this - * ensures all error handling is correct. - */ - wait_status= MDL_wait::TIMEOUT; - break; - } + /* + * The client is disconnected. Don't wait forever: + * assume it's the same as a wait timeout, this + * ensures all error handling is correct. + */ + wait_status= MDL_wait::TIMEOUT; + break; } mysql_prlock_wrlock(&lock->m_rwlock); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index a6accd52910..af3a80cb67c 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2015 Codership Oy +/* Copyright 2008-2020 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 @@ -192,7 +192,6 @@ bool wsrep_before_SE() static bool sst_complete = false; static bool sst_needed = false; -static bool sst_in_progress = false; #define WSREP_EXTEND_TIMEOUT_INTERVAL 30 #define WSREP_TIMEDWAIT_SECONDS 10 @@ -1545,11 +1544,11 @@ static void* sst_donor_thread (void* a) wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; // seqno of complete SST wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; - // SST is now in progress - sst_in_progress= true; - wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can - // operate with wsrep_ready == OFF + // We turn off wsrep_on for this THD so that it can + // operate with wsrep_ready == OFF + // We also set this SST thread THD as system thread + wsp::thd thd(FALSE, true); wsp::process proc(arg->cmd, "r", arg->env); err= proc.error(); @@ -1648,8 +1647,6 @@ wait_signal: wsrep->sst_sent (wsrep, &state_id, -err); proc.wait(); - sst_in_progress= false; - return NULL; } @@ -1824,8 +1821,3 @@ void wsrep_SE_initialized() { SE_initialized = true; } - -bool wsrep_is_sst_progress() -{ - return (sst_in_progress); -} diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 599ece4cb40..e86be3e5d93 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -413,7 +413,7 @@ process::wait () return err_; } -thd::thd (my_bool won) : init(), ptr(new THD(0)) +thd::thd (my_bool won, bool system_thread) : init(), ptr(new THD(0)) { if (ptr) { @@ -421,6 +421,8 @@ thd::thd (my_bool won) : init(), ptr(new THD(0)) ptr->store_globals(); ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog ptr->variables.wsrep_on = won; + if (system_thread) + ptr->system_thread= SYSTEM_THREAD_GENERIC; ptr->security_ctx->master_access= ~(ulong)0; lex_start(ptr); } diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index 616a6d3f457..d4d9e62a620 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -298,7 +298,7 @@ class thd public: - thd(my_bool wsrep_on); + thd(my_bool wsrep_on, bool system_thread=false); ~thd(); THD* const ptr; }; From c0e5cf79ad13fad4b34fa7d0777cc90035db93c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 25 Aug 2020 15:23:20 +0300 Subject: [PATCH 4/9] MDEV-22543: Remove orphan declaration of wsrep_is_sst_progress --- sql/wsrep_sst.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 5a749d529fb..063cab5f0f1 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -74,14 +74,12 @@ extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ -extern bool wsrep_is_sst_progress(); #else #define wsrep_SE_initialized() do { } while(0) #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) -#define wsrep_is_sst_progress() (0) #endif /* WITH_WSREP */ #endif /* WSREP_SST_H */ From 8cf8ad86d4b6f3479d80f3d8e8c2bcf463966924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 25 Aug 2020 15:32:15 +0300 Subject: [PATCH 5/9] MDEV-23547 InnoDB: Failing assertion: *len in row_upd_ext_fetch This bug was originally repeated on 10.4 after defining a UNIQUE KEY on a TEXT column, which is implemented by MDEV-371 by creating the index on a hidden virtual column. While row_vers_vc_matches_cluster() is executing in a purge thread to find out if an index entry may be removed in a secondary index that comprises a virtual column, another purge thread may process the undo log record that this check is interested in, and write a null BLOB pointer in that record. This would trip the assertion. To prevent this from occurring, we must propagate the 'missing BLOB' error up the call stack. row_upd_ext_fetch(): Return NULL when the error occurs. row_upd_index_replace_new_col_val(): Return whether the previous version was built successfully. row_upd_index_replace_new_col_vals_index_pos(): Check the error result. Yes, we would intentionally crash on this error if it occurs outside the purge thread. row_upd_index_replace_new_col_vals(): Check for the error condition, and simplify the logic. trx_undo_prev_version_build(): Check for the error condition. --- storage/innobase/include/row0upd.h | 30 +++----- storage/innobase/row/row0upd.cc | 115 ++++++++++++++--------------- storage/innobase/trx/trx0rec.cc | 6 +- 3 files changed, 72 insertions(+), 79 deletions(-) diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 04701042658..b60770b01fb 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -257,24 +257,18 @@ row_upd_index_replace_new_col_vals_index_pos( mem_heap_t* heap) /*!< in: memory heap for allocating and copying the new values */ MY_ATTRIBUTE((nonnull)); -/***********************************************************//** -Replaces the new column values stored in the update vector to the index entry -given. */ -void -row_upd_index_replace_new_col_vals( -/*===============================*/ - dtuple_t* entry, /*!< in/out: index entry where replaced; - the clustered index record must be - covered by a lock or a page latch to - prevent deletion (rollback or purge) */ - dict_index_t* index, /*!< in: index; NOTE that this may also be a - non-clustered index */ - const upd_t* update, /*!< in: an update vector built for the - CLUSTERED index so that the field number in - an upd_field is the clustered index position */ - mem_heap_t* heap) /*!< in: memory heap for allocating and - copying the new values */ - MY_ATTRIBUTE((nonnull)); +/** Replace the new column values stored in the update vector, +during trx_undo_prev_version_build(). +@param entry clustered index tuple where the values are replaced + (the clustered index leaf page latch must be held) +@param index clustered index +@param update update vector for the clustered index +@param heap memory heap for allocating and copying values +@return whether the previous version was built successfully */ +bool +row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index, + const upd_t *update, mem_heap_t *heap) + MY_ATTRIBUTE((nonnull, warn_unused_result)); /***********************************************************//** Replaces the new column values stored in the update vector. */ void diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 800c7a6d1f3..6d210cfd6bb 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1206,7 +1206,9 @@ containing also the reference to the external part @param[in,out] len input - length of prefix to fetch; output: fetched length of the prefix @param[in,out] heap heap where to allocate -@return BLOB prefix */ +@return BLOB prefix +@retval NULL if the record is incomplete (should only happen +in row_vers_vc_matches_cluster() executed concurrently with another purge) */ static byte* row_upd_ext_fetch( @@ -1221,10 +1223,7 @@ row_upd_ext_fetch( *len = btr_copy_externally_stored_field_prefix( buf, *len, page_size, data, local_len); - /* We should never update records containing a half-deleted BLOB. */ - ut_a(*len); - - return(buf); + return *len ? buf : NULL; } /** Replaces the new column value stored in the update vector in @@ -1235,9 +1234,11 @@ the given index entry field. @param[in] uf update field @param[in,out] heap memory heap for allocating and copying the new value -@param[in] page_size page size */ +@param[in] page_size page size +@return whether the previous version was built successfully */ +MY_ATTRIBUTE((nonnull, warn_unused_result)) static -void +bool row_upd_index_replace_new_col_val( dfield_t* dfield, const dict_field_t* field, @@ -1252,7 +1253,7 @@ row_upd_index_replace_new_col_val( dfield_copy_data(dfield, &uf->new_val); if (dfield_is_null(dfield)) { - return; + return true; } len = dfield_get_len(dfield); @@ -1270,6 +1271,9 @@ row_upd_index_replace_new_col_val( data = row_upd_ext_fetch(data, l, page_size, &len, heap); + if (UNIV_UNLIKELY(!data)) { + return false; + } } len = dtype_get_at_most_n_mbchars(col->prtype, @@ -1283,7 +1287,7 @@ row_upd_index_replace_new_col_val( dfield_dup(dfield, heap); } - return; + return true; } switch (uf->orig_len) { @@ -1322,6 +1326,8 @@ row_upd_index_replace_new_col_val( dfield_set_ext(dfield); break; } + + return true; } /***********************************************************//** @@ -1379,68 +1385,57 @@ row_upd_index_replace_new_col_vals_index_pos( update, i, false); } - if (uf) { - row_upd_index_replace_new_col_val( - dtuple_get_nth_field(entry, i), - field, col, uf, heap, page_size); + if (uf && UNIV_UNLIKELY(!row_upd_index_replace_new_col_val( + dtuple_get_nth_field(entry, i), + field, col, uf, heap, + page_size))) { + ut_error; } } } -/***********************************************************//** -Replaces the new column values stored in the update vector to the index entry -given. */ -void -row_upd_index_replace_new_col_vals( -/*===============================*/ - dtuple_t* entry, /*!< in/out: index entry where replaced; - the clustered index record must be - covered by a lock or a page latch to - prevent deletion (rollback or purge) */ - dict_index_t* index, /*!< in: index; NOTE that this may also be a - non-clustered index */ - const upd_t* update, /*!< in: an update vector built for the - CLUSTERED index so that the field number in - an upd_field is the clustered index position */ - mem_heap_t* heap) /*!< in: memory heap for allocating and - copying the new values */ +/** Replace the new column values stored in the update vector, +during trx_undo_prev_version_build(). +@param entry clustered index tuple where the values are replaced + (the clustered index leaf page latch must be held) +@param index clustered index +@param update update vector for the clustered index +@param heap memory heap for allocating and copying values +@return whether the previous version was built successfully */ +bool +row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index, + const upd_t *update, mem_heap_t *heap) { - ulint i; - const dict_index_t* clust_index - = dict_table_get_first_index(index->table); - const page_size_t& page_size = dict_table_page_size(index->table); + ut_ad(index.is_primary()); + const page_size_t& page_size= dict_table_page_size(index.table); - ut_ad(!index->table->skip_alter_undo); + ut_ad(!index.table->skip_alter_undo); + dtuple_set_info_bits(entry, update->info_bits); - dtuple_set_info_bits(entry, update->info_bits); + for (ulint i= 0; i < index.n_fields; i++) + { + const dict_field_t *field= &index.fields[i]; + const dict_col_t* col= dict_field_get_col(field); + const upd_field_t *uf; - for (i = 0; i < dict_index_get_n_fields(index); i++) { - const dict_field_t* field; - const dict_col_t* col; - const upd_field_t* uf; + if (col->is_virtual()) + { + const dict_v_col_t *vcol= reinterpret_cast(col); + uf= upd_get_field_by_field_no(update, vcol->v_pos, true); + } + else + uf= upd_get_field_by_field_no(update, dict_col_get_clust_pos(col, &index), + false); - field = dict_index_get_nth_field(index, i); - col = dict_field_get_col(field); - if (dict_col_is_virtual(col)) { - const dict_v_col_t* vcol = reinterpret_cast< - const dict_v_col_t*>( - col); + if (!uf) + continue; - uf = upd_get_field_by_field_no( - update, vcol->v_pos, true); - } else { - uf = upd_get_field_by_field_no( - update, - dict_col_get_clust_pos(col, clust_index), - false); - } + if (!row_upd_index_replace_new_col_val(dtuple_get_nth_field(entry, i), + field, col, uf, heap, page_size)) + return false; + } - if (uf) { - row_upd_index_replace_new_col_val( - dtuple_get_nth_field(entry, i), - field, col, uf, heap, page_size); - } - } + return true; } /** Replaces the virtual column values stored in the update vector. diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index ee022b4f1fd..623d8990381 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -2446,7 +2446,11 @@ trx_undo_prev_version_build( /* The page containing the clustered index record corresponding to entry is latched in mtr. Thus the following call is safe. */ - row_upd_index_replace_new_col_vals(entry, index, update, heap); + if (!row_upd_index_replace_new_col_vals(entry, *index, update, + heap)) { + ut_a(v_status & TRX_UNDO_PREV_IN_PURGE); + return false; + } /* Get number of externally stored columns in updated record */ const ulint n_ext = dtuple_get_n_ext(entry); From 6586bb51f3167fad9e353e8c9cd69f51e0acec21 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Aug 2020 22:21:07 +0300 Subject: [PATCH 6/9] MDEV-23467 SIGSEGV in fill_record/fill_record_n_invoke_before_triggers on INSERT DELAYED Field::make_new_field() resets invisible property (needed for "CREATE .. SELECT" f.ex.). Recover invisible property in Delayed_insert::get_local_table() (unireg_check works by the same principle). --- mysql-test/main/invisible_field.result | 6 ++++++ mysql-test/main/invisible_field.test | 8 ++++++++ sql/sql_insert.cc | 1 + 3 files changed, 15 insertions(+) diff --git a/mysql-test/main/invisible_field.result b/mysql-test/main/invisible_field.result index 053a9fd8e50..ee45567d212 100644 --- a/mysql-test/main/invisible_field.result +++ b/mysql-test/main/invisible_field.result @@ -617,3 +617,9 @@ a b 1 3 2 4 drop table t1; +# +# MDEV-23467 SIGSEGV in fill_record/fill_record_n_invoke_before_triggers on INSERT DELAYED +# +create table t1 (a int, b int invisible); +insert delayed into t1 values (1); +drop table t1; diff --git a/mysql-test/main/invisible_field.test b/mysql-test/main/invisible_field.test index 0e3994a78ce..7a48347ec29 100644 --- a/mysql-test/main/invisible_field.test +++ b/mysql-test/main/invisible_field.test @@ -271,3 +271,11 @@ select a,b from t1; #cleanup drop table t1; + +--echo # +--echo # MDEV-23467 SIGSEGV in fill_record/fill_record_n_invoke_before_triggers on INSERT DELAYED +--echo # +create table t1 (a int, b int invisible); +insert delayed into t1 values (1); +# cleanup +drop table t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a24cb61449b..b574e7ab9d7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2614,6 +2614,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) if (!(*field= (*org_field)->make_new_field(client_thd->mem_root, copy, 1))) goto error; (*field)->unireg_check= (*org_field)->unireg_check; + (*field)->invisible= (*org_field)->invisible; (*field)->orig_table= copy; // Remove connection (*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0] memdup_vcol(client_thd, (*field)->vcol_info); From 95831888e8a89a4e141e76d51dbfc0701552c824 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Aug 2020 22:21:08 +0300 Subject: [PATCH 7/9] part_records() signature fix --- sql/ha_partition.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 6a12c8a4800..b80c2174658 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1614,9 +1614,8 @@ public: return h; } - ha_rows part_records(void *_part_elem) + ha_rows part_records(partition_element *part_elem) { - partition_element *part_elem= reinterpret_cast(_part_elem); DBUG_ASSERT(m_part_info); uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; uint32 part_id= part_elem->id * sub_factor; From 65f30050aafb3821ba63a3b837c98cf4d2334254 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Mon, 24 Aug 2020 17:22:21 +0530 Subject: [PATCH 8/9] MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init When duplicates are removed from a table using a hash, if the record is a duplicate it is marked as deleted. The handler API check if the record is deleted and send an error flag HA_ERR_RECORD_DELETED. When we scan over the table if the thread is not killed then we skip the records marked as HA_ERR_RECORD_DELETED. The issue here is when a query is aborted by a user (this is happening when the LIMIT for ROWS EXAMINED is exceeded), the scan over the table does not skip the records for which HA_ERR_RECORD_DELETED is sent. It just returns an error flag HA_ERR_ABORTED_BY_USER. This error flag is not checked at the upper level and hence we hit the assert. If the query is aborted by the user we should just skip reading rows and return control to the upper levels of execution. --- mysql-test/main/subselect4.result | 31 ++++++++++++++++++++++++++ mysql-test/main/subselect4.test | 36 +++++++++++++++++++++++++++++++ sql/item_subselect.cc | 3 +++ 3 files changed, 70 insertions(+) diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index d1d3b514549..020a7064291 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2686,4 +2686,35 @@ SELECT * FROM t2; f bar DROP TABLE t1, t2; +# +# MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init +# +CREATE TABLE t1 (i1 int,v1 varchar(1),KEY (v1,i1)); +INSERT INTO t1 VALUES +(9,'y'),(4,'q'),(0,null),(0,'p'),(null,'j'); +CREATE TABLE t2 (pk int); +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t3 (v2 varchar(1)); +INSERT INTO t3 VALUES +('p'),('j'),('y'),('q'); +CREATE TABLE t4 (v2 varchar(1)); +INSERT INTO t4 VALUES +('a'),('a'),('b'),('b'),('c'),('c'), +('d'),('d'),('e'),('e'),('f'),('f'), +('g'),('g'),('h'),('h'),('i'),('i'), +('j'),('j'),('k'),('k'),('l'),('l'), +('m'),('m'),('n'),('n'),('o'),('o'), +('p'),('p'),('q'),('q'),('r'),('r'), +('s'),('s'),('t'),('t'),('u'),('u'),('v'),('v'), +('w'),('w'),('x'),('x'), (NULL),(NULL); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; +select 1 +from t2 join t1 on +('i','w') not in (select t1.v1,t4.v2 from t4,t1,t3 where t3.v2 = t1.v1) LIMIT ROWS EXAMINED 500; +1 +Warnings: +Warning 1931 Query execution was interrupted. The query examined at least 3020 rows, which exceeds LIMIT ROWS EXAMINED (500). The query result may be incomplete +SET join_cache_level= @save_join_cache_level; +DROP TABLE t1,t2,t3,t4; # End of 10.2 tests diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index 6eada9b27d9..6f5eb1f2985 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2201,4 +2201,40 @@ SELECT * FROM t2; DROP TABLE t1, t2; +--echo # +--echo # MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init +--echo # + +CREATE TABLE t1 (i1 int,v1 varchar(1),KEY (v1,i1)); +INSERT INTO t1 VALUES +(9,'y'),(4,'q'),(0,null),(0,'p'),(null,'j'); + +CREATE TABLE t2 (pk int); +INSERT INTO t2 VALUES (1),(2); + +CREATE TABLE t3 (v2 varchar(1)); +INSERT INTO t3 VALUES +('p'),('j'),('y'),('q'); + +CREATE TABLE t4 (v2 varchar(1)); +INSERT INTO t4 VALUES +('a'),('a'),('b'),('b'),('c'),('c'), +('d'),('d'),('e'),('e'),('f'),('f'), +('g'),('g'),('h'),('h'),('i'),('i'), +('j'),('j'),('k'),('k'),('l'),('l'), +('m'),('m'),('n'),('n'),('o'),('o'), +('p'),('p'),('q'),('q'),('r'),('r'), +('s'),('s'),('t'),('t'),('u'),('u'),('v'),('v'), +('w'),('w'),('x'),('x'), (NULL),(NULL); + +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; + +select 1 +from t2 join t1 on +('i','w') not in (select t1.v1,t4.v2 from t4,t1,t3 where t3.v2 = t1.v1) LIMIT ROWS EXAMINED 500; +SET join_cache_level= @save_join_cache_level; + +DROP TABLE t1,t2,t3,t4; + --echo # End of 10.2 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c32cd5ef84a..bc5111667ff 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -6281,6 +6281,9 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, while (TRUE) { error= tmp_table->file->ha_rnd_next(tmp_table->record[0]); + + if (error == HA_ERR_ABORTED_BY_USER) + break; /* This is a temp table that we fully own, there should be no other cause to stop the iteration than EOF. From 21a96581fd1dd11c5605dd89e3adbaabdf6de5eb Mon Sep 17 00:00:00 2001 From: Stepan Patryshev Date: Wed, 26 Aug 2020 04:16:55 +0300 Subject: [PATCH 9/9] MDEV-23583 Fix up community suite/galera_3nodes/disabled.def --- mysql-test/suite/galera_3nodes/disabled.def | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index 1683485981b..415da407cf7 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -1,2 +1,21 @@ +############################################################################## +# +# List the test cases that are to be disabled temporarily. +# +# Separate the test case name and the comment with ':'. +# +# : MDEV- +# +# Do not use any TAB characters for whitespace. +# +############################################################################## + +galera_ipv6_mariabackup : MDEV-23573 Could not open '../galera/include/have_mariabackup.inc' +galera_ipv6_mariabackup_section : MDEV-23574 Could not open '../galera/include/have_mariabackup.inc' +galera_ipv6_mysqldump : MDEV-23576 WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsyn : MDEV-23581 WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_rsync_section : MDEV-23580 WSREP_SST: [ERROR] rsync daemon port '16008' has been taken +galera_ipv6_xtrabackup-v2 : MDEV-23575 WSREP_SST: [ERROR] innobackupex not in path +galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798