diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-26 11:30:20 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-26 11:30:20 +0300 |
commit | 1e08e08ccb8896c1f0d2f673c16f5b92cdf7dc46 (patch) | |
tree | 2bcef1f1398c85a665743208ec0a856f884b6a84 | |
parent | 88e70f4caea34e0d7677b1fa646151b8b87dd3ab (diff) | |
parent | 6a042281bdbfe91cc39e1f6e02295bfe7eaa9d43 (diff) | |
download | mariadb-git-1e08e08ccb8896c1f0d2f673c16f5b92cdf7dc46.tar.gz |
Merge 10.3 into 10.4
-rw-r--r-- | mysql-test/main/invisible_field.result | 6 | ||||
-rw-r--r-- | mysql-test/main/invisible_field.test | 8 | ||||
-rw-r--r-- | mysql-test/main/subselect4.result | 31 | ||||
-rw-r--r-- | mysql-test/main/subselect4.test | 36 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/mdev-22543.test | 20 | ||||
-rw-r--r-- | mysql-test/suite/galera_3nodes/disabled.def | 19 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/foreign_key.result | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/foreign_key.test | 1 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/r/unique_checks_basic.result | 2 | ||||
-rw-r--r-- | sql/ha_partition.h | 3 | ||||
-rw-r--r-- | sql/item_subselect.cc | 3 | ||||
-rw-r--r-- | sql/mdl.cc | 27 | ||||
-rw-r--r-- | sql/sql_insert.cc | 1 | ||||
-rw-r--r-- | sql/sys_vars.ic | 7 | ||||
-rw-r--r-- | sql/wsrep_sst.cc | 23 | ||||
-rw-r--r-- | sql/wsrep_sst.h | 2 | ||||
-rw-r--r-- | sql/wsrep_utils.cc | 4 | ||||
-rw-r--r-- | sql/wsrep_utils.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/row0upd.h | 30 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 132 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rec.cc | 6 |
22 files changed, 222 insertions, 144 deletions
diff --git a/mysql-test/main/invisible_field.result b/mysql-test/main/invisible_field.result index a57298dd5c5..9b42b043ec6 100644 --- a/mysql-test/main/invisible_field.result +++ b/mysql-test/main/invisible_field.result @@ -621,3 +621,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/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 62309d1d232..1ec1154b16b 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2686,6 +2686,37 @@ 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 # # MDEV-19134: EXISTS() slower if ORDER BY is defined diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index 8d2ddaab09b..c9b05c4f015 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2201,6 +2201,42 @@ 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 --echo # 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/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 ':'. +# +# <testcasename> : MDEV-<xxxx> <comment> +# +# 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 diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index c2ec14e3bfe..901008753f6 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -168,7 +168,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 acf31bc6131..bbda93d160a 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/ha_partition.h b/sql/ha_partition.h index 6c9ce40d224..7d10dc19683 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1620,9 +1620,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<partition_element *>(_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; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 578f0ded00e..513aad737cd 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -6318,6 +6318,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. diff --git a/sql/mdl.cc b/sql/mdl.cc index 97135890f09..54128c2ee97 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -24,9 +24,6 @@ #include <mysql/plugin.h> #include <mysql/service_thd_wait.h> #include <mysql/psi/mysql_stage.h> -#ifdef WITH_WSREP -#include "wsrep_sst.h" -#endif #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -2328,26 +2325,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/sql_insert.cc b/sql/sql_insert.cc index 8d0e08d8c8c..52641291eb2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2638,6 +2638,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); diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 94bfb3bb1bb..9ab424b3f8d 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -1817,13 +1817,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_CSTRING *base) diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 396b262abb4..b553886e9fd 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2017 Codership Oy <http://www.codership.com> +/* Copyright 2008-2020 Codership Oy <http://www.codership.com> 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 @@ -54,7 +54,6 @@ my_bool wsrep_sst_donor_rejects_queries= FALSE; bool sst_joiner_completed = false; bool sst_donor_completed = false; -bool sst_needed = false; struct sst_thread_arg { @@ -308,7 +307,6 @@ bool wsrep_before_SE() && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); } -static bool sst_in_progress = false; // Signal end of SST static void wsrep_sst_complete (THD* thd, int const rcode) @@ -1627,12 +1625,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(); @@ -1734,10 +1731,7 @@ wait_signal: proc.wait(); wsrep_donor_monitor_end(); - sst_in_progress= false; - - - return NULL; + return nullptr; } static int sst_donate_other (const char* method, @@ -1889,8 +1883,3 @@ int wsrep_sst_donate(const std::string& msg, return (ret >= 0 ? 0 : 1); } - -bool wsrep_is_sst_progress() -{ - return (sst_in_progress); -} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 50f2d362c5a..2389db4abe7 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -77,7 +77,6 @@ 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(); /** Return a string containing the state transfer request string. @@ -103,6 +102,5 @@ int wsrep_sst_donate(const std::string& request, #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 /* WSREP_SST_H */ diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 49ea78a3872..4cf131fd974 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -417,7 +417,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) { @@ -426,6 +426,8 @@ thd::thd (my_bool won) : init(), ptr(new THD(0)) wsrep_store_threadvars(ptr); 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 4b010816a40..974c623521e 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -303,7 +303,7 @@ class thd public: - thd(my_bool wsrep_on); + thd(my_bool wsrep_on, bool system_thread=false); ~thd(); THD* const ptr; }; diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index c5a0a3bf4f9..2b06d406296 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -224,24 +224,18 @@ row_upd_index_replace_new_col_vals_index_pos( const upd_t* update, mem_heap_t* heap) 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 1f30a428d74..398149f8b58 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1127,7 +1127,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( @@ -1142,10 +1144,7 @@ row_upd_ext_fetch( *len = btr_copy_externally_stored_field_prefix( buf, *len, zip_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 @@ -1156,9 +1155,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] zip_size ROW_FORMAT=COMPRESSED page size, or 0 */ +@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 +@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, @@ -1173,13 +1174,13 @@ 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); data = static_cast<const byte*>(dfield_get_data(dfield)); - if (field && field->prefix_len > 0) { + if (field->prefix_len > 0) { ibool fetch_ext = dfield_is_ext(dfield) && len < (ulint) field->prefix_len + BTR_EXTERN_FIELD_REF_SIZE; @@ -1191,6 +1192,9 @@ row_upd_index_replace_new_col_val( data = row_upd_ext_fetch(data, l, zip_size, &len, heap); + if (UNIV_UNLIKELY(!data)) { + return false; + } } len = dtype_get_at_most_n_mbchars(col->prtype, @@ -1204,7 +1208,7 @@ row_upd_index_replace_new_col_val( dfield_dup(dfield, heap); } - return; + return true; } switch (uf->orig_len) { @@ -1243,6 +1247,8 @@ row_upd_index_replace_new_col_val( dfield_set_ext(dfield); break; } + + return true; } /** Apply an update vector to an metadata entry. @@ -1289,8 +1295,11 @@ row_upd_index_replace_metadata( f -= f > first; const dict_field_t* field = dict_index_get_nth_field(index, f); - row_upd_index_replace_new_col_val(dfield, field, field->col, - uf, heap, zip_size); + if (!row_upd_index_replace_new_col_val(dfield, field, + field->col, + uf, heap, zip_size)) { + ut_error; + } } ut_ad(found_mblob); @@ -1341,68 +1350,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, zip_size); + if (uf && UNIV_UNLIKELY(!row_upd_index_replace_new_col_val( + dtuple_get_nth_field(entry, i), + field, col, uf, heap, + zip_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 ulint zip_size = index->table->space->zip_size(); + ut_ad(index.is_primary()); + const ulint zip_size= index.table->space->zip_size(); - ut_ad(!index->table->skip_alter_undo); - - dtuple_set_info_bits(entry, update->info_bits); + ut_ad(!index.table->skip_alter_undo); + dtuple_set_info_bits(entry, update->info_bits); - 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; - - field = dict_index_get_nth_field(index, i); - col = dict_field_get_col(field); - if (col->is_virtual()) { - const dict_v_col_t* vcol = reinterpret_cast< - const dict_v_col_t*>( - 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, clust_index), - false); - } + 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; + + if (col->is_virtual()) + { + const dict_v_col_t *vcol= reinterpret_cast<const dict_v_col_t*>(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); + + if (!uf) + continue; + + if (!row_upd_index_replace_new_col_val(dtuple_get_nth_field(entry, i), + field, col, uf, heap, zip_size)) + return false; + } - if (uf) { - row_upd_index_replace_new_col_val( - dtuple_get_nth_field(entry, i), - field, col, uf, heap, zip_size); - } - } + return true; } /** Replaces the virtual column values stored in the update vector. @@ -2421,7 +2419,7 @@ row_upd_sec_index_entry( #ifdef UNIV_DEBUG mtr_commit(&mtr); mtr_start(&mtr); - ut_ad(btr_validate_index(index, 0)); + ut_ad(btr_validate_index(index, 0) == DB_SUCCESS); ut_ad(0); #endif /* UNIV_DEBUG */ break; diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 7316fc15b0f..b164daf0ecc 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -2476,7 +2476,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 = index->is_primary() |