From 1872a142b5f827758a68e7ee745b3451f5dbea2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 7 Sep 2022 11:58:04 +0300 Subject: [PATCH 1/8] MDEV-10003 main.range_innodb retuns a wrong number of rows in EXPLAIN Let us specify STATS_AUTO_RECALC=0 for the failing section of the test. It is possible that this test started failing sporadically ever since commit 9608773f75e2ca21491ef6825c3616cdc96d1ca5 was applied and tests no longer globally disable the InnoDB persistent statistics. --- mysql-test/main/range_innodb.result | 6 +++--- mysql-test/main/range_innodb.test | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/range_innodb.result b/mysql-test/main/range_innodb.result index 1d98fad0295d7..6cd1c133b93dc 100644 --- a/mysql-test/main/range_innodb.result +++ b/mysql-test/main/range_innodb.result @@ -44,13 +44,13 @@ drop table t0,t1,t2; create table t1 ( pk int, a int, b int, primary key (pk), index idx1(b), index idx2(b) -) engine=innodb; +) engine=innodb STATS_AUTO_RECALC=0; Warnings: Note 1831 Duplicate index `idx2`. This is deprecated and will be disallowed in a future release insert into t1 values (1,6,0),(2,1,0),(3,5,2),(4,8,0); -create table t2 (c int) engine=innodb; +create table t2 (c int) engine=innodb STATS_AUTO_RECALC=0; insert into t2 values (1),(2); -create table t3 (d int) engine=innodb; +create table t3 (d int) engine=innodb STATS_AUTO_RECALC=0; insert into t3 values (3),(-1),(4); set @save_optimizer_switch=@@optimizer_switch; set optimizer_switch='extended_keys=on'; diff --git a/mysql-test/main/range_innodb.test b/mysql-test/main/range_innodb.test index 8b9771d1d1e6d..df0fff403a85a 100644 --- a/mysql-test/main/range_innodb.test +++ b/mysql-test/main/range_innodb.test @@ -54,11 +54,11 @@ drop table t0,t1,t2; create table t1 ( pk int, a int, b int, primary key (pk), index idx1(b), index idx2(b) -) engine=innodb; +) engine=innodb STATS_AUTO_RECALC=0; insert into t1 values (1,6,0),(2,1,0),(3,5,2),(4,8,0); -create table t2 (c int) engine=innodb; +create table t2 (c int) engine=innodb STATS_AUTO_RECALC=0; insert into t2 values (1),(2); -create table t3 (d int) engine=innodb; +create table t3 (d int) engine=innodb STATS_AUTO_RECALC=0; insert into t3 values (3),(-1),(4); set @save_optimizer_switch=@@optimizer_switch; From bacaf2d4f4c6d77a0b6c1ae4daddd19f81ef6fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 7 Sep 2022 12:57:53 +0300 Subject: [PATCH 2/8] MDEV-29342 Assertion failure in file que0que.cc line 728 Additional fixes for 10.6: fts_sync_commit(): Release cache->lock also on rollback. fts_sync_write_words(): Avoid a crash if an error occurs, by stopping at the first error. fts_add_doc_by_id(): Sync the doc id only after adding the doc id to the cache. --- mysql-test/suite/innodb_fts/r/misc_debug2.result | 8 ++++---- mysql-test/suite/innodb_fts/t/misc_debug2.test | 8 ++++---- storage/innobase/fts/fts0fts.cc | 14 ++++++++------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/innodb_fts/r/misc_debug2.result b/mysql-test/suite/innodb_fts/r/misc_debug2.result index f1ebef6175fd5..2587b1c74b03a 100644 --- a/mysql-test/suite/innodb_fts/r/misc_debug2.result +++ b/mysql-test/suite/innodb_fts/r/misc_debug2.result @@ -11,12 +11,12 @@ DROP TABLE mdev21563; # CREATE TABLE t1(f1 CHAR(100), FULLTEXT idx(f1))ENGINE=InnoDB; INSERT INTO t1 VALUES('mysql'), ('innodb'); -set debug_dbug="+d,fts_instrument_sync_debug"; +set debug_dbug="+d,fts_instrument_sync_request"; INSERT INTO t1 VALUES('test'); -set debug_dbug="-d,fts_instrument_sync_debug"; +set debug_dbug="-d,fts_instrument_sync_request"; INSERT INTO t1 VALUES('This is a fts issue'); # restart -set debug_dbug="+d,fts_instrument_sync_debug"; +set debug_dbug="+d,fts_instrument_sync_request"; UPDATE t1 SET f1="mariadb"; -set debug_dbug="-d,fts_instrument_sync_debug"; +set debug_dbug="-d,fts_instrument_sync_request"; DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/misc_debug2.test b/mysql-test/suite/innodb_fts/t/misc_debug2.test index 1ba77f2481e38..eb2f80ed24a98 100644 --- a/mysql-test/suite/innodb_fts/t/misc_debug2.test +++ b/mysql-test/suite/innodb_fts/t/misc_debug2.test @@ -16,12 +16,12 @@ DROP TABLE mdev21563; --echo # CREATE TABLE t1(f1 CHAR(100), FULLTEXT idx(f1))ENGINE=InnoDB; INSERT INTO t1 VALUES('mysql'), ('innodb'); -set debug_dbug="+d,fts_instrument_sync_debug"; +set debug_dbug="+d,fts_instrument_sync_request"; INSERT INTO t1 VALUES('test'); -set debug_dbug="-d,fts_instrument_sync_debug"; +set debug_dbug="-d,fts_instrument_sync_request"; INSERT INTO t1 VALUES('This is a fts issue'); --source include/restart_mysqld.inc -set debug_dbug="+d,fts_instrument_sync_debug"; +set debug_dbug="+d,fts_instrument_sync_request"; UPDATE t1 SET f1="mariadb"; -set debug_dbug="-d,fts_instrument_sync_debug"; +set debug_dbug="-d,fts_instrument_sync_request"; DROP TABLE t1; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index ae270bf72b243..faf598ddd7287 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -3314,7 +3314,7 @@ fts_add_doc_by_id( dict_index_t* fts_id_index; ibool is_id_cluster; fts_cache_t* cache = ftt->table->fts->cache; - + bool need_sync= false; ut_ad(cache->get_docs); /* If Doc ID has been supplied by the user, then the table @@ -3443,7 +3443,7 @@ fts_add_doc_by_id( shouldn't hold the cache lock for longer time. So cache should sync whenever cache size exceeds 512 KB */ - bool need_sync = + need_sync = cache->total_size > 512*1024; mysql_mutex_unlock(&table->fts->cache->lock); @@ -3464,10 +3464,6 @@ fts_add_doc_by_id( need_sync= true; ); - if (need_sync) { - fts_sync_table(table); - } - mtr_start(&mtr); if (i < num_idx - 1) { @@ -3493,6 +3489,10 @@ fts_add_doc_by_id( ut_free(pcur.old_rec_buf); mem_heap_free(heap); + + if (need_sync) { + fts_sync_table(table); + } } @@ -3898,6 +3898,7 @@ fts_sync_write_words( ib::error() << "(" << error << ") writing" " word node to FTS auxiliary index table " << table->name; + break; } } @@ -3999,6 +4000,7 @@ fts_sync_commit( mysql_mutex_unlock(&cache->lock); fts_sql_commit(trx); } else { + mysql_mutex_unlock(&cache->lock); fts_sql_rollback(trx); ib::error() << "(" << error << ") during SYNC of " "table " << sync->table->name; From dd092bc6ebb23a6a93da284bc81175f2e0c54896 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 7 Sep 2022 19:58:55 +1000 Subject: [PATCH 3/8] Deb: add kinetic to autobake (#2250) --- debian/autobake-deb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh index 14e9214dde9db..9ab06d41a5fda 100755 --- a/debian/autobake-deb.sh +++ b/debian/autobake-deb.sh @@ -87,7 +87,7 @@ case "${LSBNAME}" in ;& focal) ;& - impish|jammy) + impish|jammy|kinetic) # mariadb-plugin-rocksdb s390x not supported by us (yet) # ubuntu doesn't support mips64el yet, so keep this just # in case something changes. From 9a8faeea142ea6f575419799c9439f4673971573 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 7 Sep 2022 13:49:49 +0200 Subject: [PATCH 4/8] MDEV-18353 - minor cleanup Do not repeat yourself. Instead of having the same DBUG_EXECUTE_IF code in threadpool and thread-per-connection, add this code to setup_connection_thread_globals() which is executed in all scheduling modes. --- sql/sql_connect.cc | 16 ++++++++-------- sql/threadpool_common.cc | 8 -------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 733d281efd5ae..17beb413e7f22 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1107,6 +1107,14 @@ static int check_connection(THD *thd) bool setup_connection_thread_globals(THD *thd) { + + DBUG_EXECUTE_IF("CONNECT_wait", { + extern MYSQL_SOCKET unix_sock; + DBUG_ASSERT(unix_sock.fd >= 0); + while (unix_sock.fd >= 0) + my_sleep(1000); + }); + if (thd->store_globals()) { close_connection(thd, ER_OUT_OF_RESOURCES); @@ -1360,14 +1368,6 @@ void do_handle_one_connection(CONNECT *connect) return; } - DBUG_EXECUTE_IF("CONNECT_wait", - { - extern MYSQL_SOCKET unix_sock; - DBUG_ASSERT(unix_sock.fd >= 0); - while (unix_sock.fd >= 0) - my_sleep(1000); - }); - /* If a thread was created to handle this connection: increment slow_launch_threads counter if it took more than diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 4195bf21e4802..38848f3c23702 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -222,14 +222,6 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) { THD *thd= NULL; - DBUG_EXECUTE_IF("CONNECT_wait", - { - extern MYSQL_SOCKET unix_sock; - DBUG_ASSERT(unix_sock.fd >= 0); - while (unix_sock.fd >= 0) - my_sleep(1000); - }); - /* Create a new connection context: mysys_thread_var and PSI thread Store them in THD. From bd7ff02a6aef2dcb0eb67b2e9a4e48370c438355 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 7 Sep 2022 16:41:21 +0200 Subject: [PATCH 5/8] Fix CMake 3.24 warning by setting a policy --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5074a9750387..06ff1cc662e5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ PROJECT(MySQL) # in RPM's: #set(CPACK_RPM_SPEC_MORE_DEFINE "%define __spec_install_post /bin/true") -FOREACH(p CMP0022 CMP0046 CMP0040 CMP0048 CMP0054 CMP0075 CMP0069) +FOREACH(p CMP0022 CMP0046 CMP0040 CMP0048 CMP0054 CMP0075 CMP0069 CMP0135) IF(POLICY ${p}) CMAKE_POLICY(SET ${p} NEW) ENDIF() From 0fa4dd0747bb12479662952e7fe6ae2fffff737b Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Wed, 7 Sep 2022 21:41:29 +0300 Subject: [PATCH 6/8] MDEV-29433 innodb.lock_delete_updated is unstable Use suspend thread syncpoint instead of include/wait_condition.inc to make sure DELETE created waiting lock before the next UPDATE begins locking. --- mysql-test/suite/innodb/r/lock_delete_updated.result | 4 +++- mysql-test/suite/innodb/t/lock_delete_updated.test | 12 +++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/innodb/r/lock_delete_updated.result b/mysql-test/suite/innodb/r/lock_delete_updated.result index c2cd47b5dd9f2..3ce63be36ab59 100644 --- a/mysql-test/suite/innodb/r/lock_delete_updated.result +++ b/mysql-test/suite/innodb/r/lock_delete_updated.result @@ -1,11 +1,12 @@ CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t VALUES (3); BEGIN; -connection default; UPDATE t SET a = 2; connect con1,localhost,root; +SET DEBUG_SYNC="lock_wait_start SIGNAL del_locked"; DELETE FROM t; connection default; +SET DEBUG_SYNC="now WAIT_FOR del_locked"; UPDATE t SET a = 1; COMMIT; connection con1; @@ -17,4 +18,5 @@ connection default; SELECT count(*) FROM t; count(*) 1 +SET DEBUG_SYNC="reset"; DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/lock_delete_updated.test b/mysql-test/suite/innodb/t/lock_delete_updated.test index 4621d5fcd2b7c..1f7b13144e4f8 100644 --- a/mysql-test/suite/innodb/t/lock_delete_updated.test +++ b/mysql-test/suite/innodb/t/lock_delete_updated.test @@ -1,23 +1,20 @@ --source include/have_innodb.inc --source include/count_sessions.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t VALUES (3); BEGIN; - -connection default; UPDATE t SET a = 2; connect con1,localhost,root; +SET DEBUG_SYNC="lock_wait_start SIGNAL del_locked"; send DELETE FROM t; connection default; -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = "Updating" and info = "DELETE FROM t"; ---source include/wait_condition.inc - +SET DEBUG_SYNC="now WAIT_FOR del_locked"; UPDATE t SET a = 1; COMMIT; @@ -30,5 +27,6 @@ connection default; --echo # The above DELETE must delete all the rows in the table, so the --echo # following SELECT must show 0 rows. SELECT count(*) FROM t; +SET DEBUG_SYNC="reset"; DROP TABLE t; --source include/wait_until_count_sessions.inc From d2e649aec2b67b224c4090c7c13a8c541bad9c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Sep 2022 14:57:50 +0300 Subject: [PATCH 7/8] MDEV-29440 InnoDB instant ALTER TABLE recovery must use READ UNCOMMITTED In commit 8f8ba758559e473f643baa0a0601d321c42517b9 (MDEV-27234) the data dictionary recovery was changed to use READ COMMITTED so that table-rebuild operations (OPTIMIZE TABLE, TRUNCATE TABLE, some forms of ALTER TABLE) would be recovered correctly. However, for operations that avoid a table rebuild thanks to being able to instantly ADD, DROP or reorder columns, recovery must use the READ UNCOMMITTED isolation level so that changes to the hidden metadata record can be rolled back. We will detect instant operations by detecting uncommitted changes to SYS_COLUMNS in case there is no uncommitted change of SYS_TABLES.ID for the table. In any table-rebuilding DDL operation, the SYS_TABLES.ID (and likely also the table name) will be updated. As part of rolling back the instant ALTER TABLE operation, after the operation on the hidden metadata record has been rolled back, a rollback of an INSERT into SYS_COLUMNS in row_undo_ins_remove_clust_rec() will invoke trx_t::evict_table() to discard the READ UNCOMMITTED definition of the table. After that, subsequent recovery steps will load and use the correct table definition. Reviewed by: Thirunarayanan Balathandayuthapani Tested by: Matthias Leich --- .../suite/innodb/r/instant_alter_crash.result | 22 +- .../suite/innodb/t/instant_alter_crash.test | 26 +- storage/innobase/dict/dict0load.cc | 302 +++++++++++------- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/handler/handler0alter.cc | 4 +- storage/innobase/handler/i_s.cc | 2 +- storage/innobase/include/dict0load.h | 5 +- storage/innobase/row/row0mysql.cc | 2 +- 8 files changed, 234 insertions(+), 131 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_crash.result b/mysql-test/suite/innodb/r/instant_alter_crash.result index 556e8d415f4e5..f017f8603010e 100644 --- a/mysql-test/suite/innodb/r/instant_alter_crash.result +++ b/mysql-test/suite/innodb/r/instant_alter_crash.result @@ -176,5 +176,25 @@ t3 CREATE TABLE `t3` ( PRIMARY KEY (`id`), UNIQUE KEY `v2` (`v2`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 -DROP TABLE t1,t2,t3; +DROP TABLE t2,t3; +# +# MDEV-29440 InnoDB instant ALTER TABLE recovery wrongly uses +# READ COMMITTED isolation level instead of READ UNCOMMITTED +# +CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); +connect ddl, localhost, root; +SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; +ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; +connection default; +SET DEBUG_SYNC='now WAIT_FOR ddl'; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1; +# Kill the server +disconnect ddl; +# restart +CHECK TABLE t2; +Table Op Msg_type Msg_text +test.t2 check status OK +DROP TABLE t1,t2; db.opt diff --git a/mysql-test/suite/innodb/t/instant_alter_crash.test b/mysql-test/suite/innodb/t/instant_alter_crash.test index ddeaa6885e6d4..4d211ece106b1 100644 --- a/mysql-test/suite/innodb/t/instant_alter_crash.test +++ b/mysql-test/suite/innodb/t/instant_alter_crash.test @@ -198,6 +198,30 @@ disconnect ddl; SHOW CREATE TABLE t1; SHOW CREATE TABLE t2; SHOW CREATE TABLE t3; -DROP TABLE t1,t2,t3; +DROP TABLE t2,t3; + +--echo # +--echo # MDEV-29440 InnoDB instant ALTER TABLE recovery wrongly uses +--echo # READ COMMITTED isolation level instead of READ UNCOMMITTED +--echo # +CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); + +connect ddl, localhost, root; +SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; +--send +ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR ddl'; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1; + +--source include/kill_mysqld.inc +disconnect ddl; +--source include/start_mysqld.inc + +CHECK TABLE t2; +DROP TABLE t1,t2; --list_files $MYSQLD_DATADIR/test diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 27fe348956996..b93b5f8edbc74 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -74,6 +74,8 @@ dict_load_index_low( byte* table_id, /*!< in/out: table id (8 bytes), an "in" value if mtr and "out" when !mtr */ + bool uncommitted, /*!< in: false=READ COMMITTED, + true=READ UNCOMMITTED */ mem_heap_t* heap, /*!< in/out: temporary memory heap */ const rec_t* rec, /*!< in: SYS_INDEXES record */ mtr_t* mtr, /*!< in/out: mini-transaction, @@ -83,30 +85,30 @@ dict_load_index_low( dict_index_t** index); /*!< out,own: index, or NULL */ /** Load a table column definition from a SYS_COLUMNS record to dict_table_t. -@return error message -@retval NULL on success */ -static -const char* -dict_load_column_low( - dict_table_t* table, /*!< in/out: table, could be NULL - if we just populate a dict_column_t - struct with information from - a SYS_COLUMNS record */ - mem_heap_t* heap, /*!< in/out: memory heap - for temporary storage */ - dict_col_t* column, /*!< out: dict_column_t to fill, - or NULL if table != NULL */ - table_id_t* table_id, /*!< out: table id */ - const char** col_name, /*!< out: column name */ - const rec_t* rec, /*!< in: SYS_COLUMNS record */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ulint* nth_v_col); /*!< out: if not NULL, this - records the "n" of "nth" virtual - column */ +@param table table, or nullptr if the output will be in column +@param use_uncommitted 0=READ COMMITTED, 1=detect, 2=READ UNCOMMITTED +@param heap memory heap for temporary storage +@param column pointer to output buffer, or nullptr if table!=nullptr +@param table_id table identifier +@param col_name column name +@param rec SYS_COLUMNS record +@param mtr mini-transaction +@param nth_v_col nullptr, or pointer to a counter of virtual columns +@return error message +@retval nullptr on success */ +static const char *dict_load_column_low(dict_table_t *table, + unsigned use_uncommitted, + mem_heap_t *heap, dict_col_t *column, + table_id_t *table_id, + const char **col_name, + const rec_t *rec, + mtr_t *mtr, + ulint *nth_v_col); /** Load a virtual column "mapping" (to base columns) information from a SYS_VIRTUAL record @param[in,out] table table +@param[in] uncommitted false=READ COMMITTED, true=READ UNCOMMITTED @param[in,out] column mapped base column's dict_column_t @param[in,out] table_id table id @param[in,out] pos virtual column position @@ -118,6 +120,7 @@ static const char* dict_load_virtual_low( dict_table_t* table, + bool uncommitted, dict_col_t** column, table_id_t* table_id, ulint* pos, @@ -133,6 +136,8 @@ dict_load_field_low( byte* index_id, /*!< in/out: index id (8 bytes) an "in" value if index != NULL and "out" if index == NULL */ + bool uncommitted, /*!< in: false=READ COMMITTED, + true=READ UNCOMMITTED */ dict_index_t* index, /*!< in/out: index, could be NULL if we just populate a dict_field_t struct with information from @@ -251,18 +256,16 @@ dict_process_sys_indexes_rec( dict_index_t* index, /*!< out: index to be filled */ table_id_t* table_id) /*!< out: index table id */ { - const char* err_msg; - byte buf[8]; + byte buf[8]; - ut_d(index->is_dummy = true); - ut_d(index->in_instant_init = false); + ut_d(index->is_dummy = true); + ut_d(index->in_instant_init = false); - /* Parse the record, and get "dict_index_t" struct filled */ - err_msg = dict_load_index_low(buf, heap, rec, nullptr, nullptr, &index); - - *table_id = mach_read_from_8(buf); - - return(err_msg); + /* Parse the record, and get "dict_index_t" struct filled */ + const char *err_msg= dict_load_index_low(buf, false, heap, rec, + nullptr, nullptr, &index); + *table_id= mach_read_from_8(buf); + return err_msg; } /********************************************************************//** @@ -283,7 +286,7 @@ dict_process_sys_columns_rec( const char* err_msg; /* Parse the record, and get "dict_col_t" struct filled */ - err_msg = dict_load_column_low(NULL, heap, column, + err_msg = dict_load_column_low(NULL, 0, heap, column, table_id, col_name, rec, nullptr, nth_v_col); @@ -304,7 +307,8 @@ dict_process_sys_virtual_rec( ulint* pos, ulint* base_pos) { - return dict_load_virtual_low(nullptr, nullptr, table_id, pos, base_pos, rec); + return dict_load_virtual_low(nullptr, false, nullptr, table_id, + pos, base_pos, rec); } /********************************************************************//** @@ -328,7 +332,7 @@ dict_process_sys_fields_rec( mach_write_to_8(last_index_id, last_id); - err_msg = dict_load_field_low(buf, NULL, sys_field, + err_msg = dict_load_field_low(buf, false, nullptr, sys_field, pos, last_index_id, heap, nullptr, rec); *index_id = mach_read_from_8(buf); @@ -632,6 +636,7 @@ enum table_read_status { READ_OK= 0, READ_ERROR, READ_NOT_FOUND }; /** Read and return 5 integer fields from a SYS_TABLES record. @param[in] rec A record of SYS_TABLES +@param[in] uncommitted true=use READ UNCOMMITTED, false=READ COMMITTED @param[in] mtr mini-transaction @param[out] table_id Pointer to the table_id for this table @param[out] space_id Pointer to the space_id for this table @@ -646,6 +651,7 @@ static table_read_status dict_sys_tables_rec_read( const rec_t* rec, + bool uncommitted, mtr_t* mtr, table_id_t* table_id, ulint* space_id, @@ -663,7 +669,7 @@ dict_sys_tables_rec_read( rec, DICT_FLD__SYS_TABLES__DB_TRX_ID, &len); ut_ad(len == 6 || len == UNIV_SQL_NULL); trx_id_t id = len == 6 ? trx_read_trx_id(field) : 0; - if (id && trx_sys.find(nullptr, id, false)) { + if (id && !uncommitted && trx_sys.find(nullptr, id, false)) { const auto savepoint = mtr->get_savepoint(); heap = mem_heap_create(1024); dict_index_t* index = UT_LIST_GET_FIRST( @@ -906,7 +912,8 @@ void dict_check_tablespaces_and_store_max_id() DBUG_PRINT("dict_check_sys_tables", ("name: %*.s", static_cast(len), field)); - if (dict_sys_tables_rec_read(rec, &mtr, &table_id, &space_id, + if (dict_sys_tables_rec_read(rec, false, + &mtr, &table_id, &space_id, &n_cols, &flags, &flags2, nullptr) != READ_OK || space_id == TRX_SYS_SPACE) { @@ -976,29 +983,31 @@ void dict_check_tablespaces_and_store_max_id() /** Error message for a delete-marked record in dict_load_column_low() */ static const char *dict_load_column_del= "delete-marked record in SYS_COLUMNS"; +/** Error message for a missing record in dict_load_column_low() */ static const char *dict_load_column_none= "SYS_COLUMNS record not found"; +/** Message for incomplete instant ADD/DROP in dict_load_column_low() */ +static const char *dict_load_column_instant= "incomplete instant ADD/DROP"; /** Load a table column definition from a SYS_COLUMNS record to dict_table_t. -@return error message -@retval NULL on success */ -static -const char* -dict_load_column_low( - dict_table_t* table, /*!< in/out: table, could be NULL - if we just populate a dict_column_t - struct with information from - a SYS_COLUMNS record */ - mem_heap_t* heap, /*!< in/out: memory heap - for temporary storage */ - dict_col_t* column, /*!< out: dict_column_t to fill, - or NULL if table != NULL */ - table_id_t* table_id, /*!< out: table id */ - const char** col_name, /*!< out: column name */ - const rec_t* rec, /*!< in: SYS_COLUMNS record */ - mtr_t* mtr, /*!< in/out: mini-transaction */ - ulint* nth_v_col) /*!< out: if not NULL, this - records the "n" of "nth" virtual - column */ +@param table table, or nullptr if the output will be in column +@param use_uncommitted 0=READ COMMITTED, 1=detect, 2=READ UNCOMMITTED +@param heap memory heap for temporary storage +@param column pointer to output buffer, or nullptr if table!=nullptr +@param table_id table identifier +@param col_name column name +@param rec SYS_COLUMNS record +@param mtr mini-transaction +@param nth_v_col nullptr, or pointer to a counter of virtual columns +@return error message +@retval nullptr on success */ +static const char *dict_load_column_low(dict_table_t *table, + unsigned use_uncommitted, + mem_heap_t *heap, dict_col_t *column, + table_id_t *table_id, + const char **col_name, + const rec_t *rec, + mtr_t *mtr, + ulint *nth_v_col) { char* name; const byte* field; @@ -1044,7 +1053,11 @@ dict_load_column_low( const trx_id_t trx_id = trx_read_trx_id(field); - if (trx_id && mtr && trx_sys.find(nullptr, trx_id, false)) { + if (trx_id && mtr && use_uncommitted < 2 + && trx_sys.find(nullptr, trx_id, false)) { + if (use_uncommitted) { + return dict_load_column_instant; + } const auto savepoint = mtr->get_savepoint(); dict_index_t* index = UT_LIST_GET_FIRST( dict_sys.sys_columns->indexes); @@ -1173,6 +1186,7 @@ static const char *dict_load_virtual_none= "SYS_VIRTUAL record not found"; /** Load a virtual column "mapping" (to base columns) information from a SYS_VIRTUAL record @param[in,out] table table +@param[in] uncommitted false=READ COMMITTED, true=READ UNCOMMITTED @param[in,out] column mapped base column's dict_column_t @param[in,out] table_id table id @param[in,out] pos virtual column position @@ -1184,6 +1198,7 @@ static const char* dict_load_virtual_low( dict_table_t* table, + bool uncommitted, dict_col_t** column, table_id_t* table_id, ulint* pos, @@ -1247,10 +1262,11 @@ dict_load_virtual_low( const trx_id_t trx_id = trx_read_trx_id(field); - if (trx_id && column && trx_sys.find(nullptr, trx_id, false)) { + if (trx_id && column && !uncommitted + && trx_sys.find(nullptr, trx_id, false)) { if (!rec_get_deleted_flag(rec, 0)) { return dict_load_virtual_none; - } + } } else if (rec_get_deleted_flag(rec, 0)) { ut_ad(trx_id != 0); return dict_load_virtual_del; @@ -1263,16 +1279,17 @@ dict_load_virtual_low( return(NULL); } -/********************************************************************//** -Loads definitions for table columns. */ +/** Load the definitions for table columns. +@param table table +@param use_uncommitted 0=READ COMMITTED, 1=detect, 2=READ UNCOMMITTED +@param heap memory heap for temporary storage +@return error code +@retval DB_SUCCESS on success +@retval DB_SUCCESS_LOCKED_REC on success if use_uncommitted=1 +and instant ADD/DROP/reorder was detected */ MY_ATTRIBUTE((nonnull, warn_unused_result)) -static -dberr_t -dict_load_columns( -/*==============*/ - dict_table_t* table, /*!< in/out: table */ - mem_heap_t* heap) /*!< in/out: memory heap - for temporary storage */ +static dberr_t dict_load_columns(dict_table_t *table, unsigned use_uncommitted, + mem_heap_t *heap) { btr_pcur_t pcur; mtr_t mtr; @@ -1320,7 +1337,8 @@ dict_load_columns( const rec_t* rec = btr_pcur_get_rec(&pcur); err_msg = btr_pcur_is_on_user_rec(&pcur) - ? dict_load_column_low(table, heap, NULL, NULL, + ? dict_load_column_low(table, use_uncommitted, + heap, NULL, NULL, &name, rec, &mtr, &nth_v_col) : dict_load_column_none; @@ -1328,6 +1346,9 @@ dict_load_columns( } else if (err_msg == dict_load_column_del) { n_skipped++; goto next_rec; + } else if (err_msg == dict_load_column_instant) { + err = DB_SUCCESS_LOCKED_REC; + goto func_exit; } else if (err_msg == dict_load_column_none && strstr(table->name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { @@ -1384,13 +1405,13 @@ dict_load_columns( } /** Loads SYS_VIRTUAL info for one virtual column -@param[in,out] table table -@param[in] nth_v_col virtual column sequence num -*/ +@param table table definition +@param uncommitted false=READ COMMITTED, true=READ UNCOMMITTED +@param nth_v_col virtual column position */ MY_ATTRIBUTE((nonnull, warn_unused_result)) static dberr_t -dict_load_virtual_col(dict_table_t *table, ulint nth_v_col) +dict_load_virtual_col(dict_table_t *table, bool uncommitted, ulint nth_v_col) { const dict_v_col_t* v_col = dict_table_get_nth_v_col(table, nth_v_col); @@ -1440,7 +1461,7 @@ dict_load_virtual_col(dict_table_t *table, ulint nth_v_col) ulint pos; const char* err_msg = btr_pcur_is_on_user_rec(&pcur) - ? dict_load_virtual_low(table, + ? dict_load_virtual_low(table, uncommitted, &v_col->base_col[i - skipped], NULL, &pos, NULL, @@ -1470,12 +1491,13 @@ dict_load_virtual_col(dict_table_t *table, ulint nth_v_col) } /** Loads info from SYS_VIRTUAL for virtual columns. -@param[in,out] table table */ +@param table table definition +@param uncommitted false=READ COMMITTED, true=READ UNCOMMITTED */ MY_ATTRIBUTE((nonnull, warn_unused_result)) -static dberr_t dict_load_virtual(dict_table_t *table) +static dberr_t dict_load_virtual(dict_table_t *table, bool uncommitted) { for (ulint i= 0; i < table->n_v_cols; i++) - if (dberr_t err= dict_load_virtual_col(table, i)) + if (dberr_t err= dict_load_virtual_col(table, uncommitted, i)) return err; return DB_SUCCESS; } @@ -1494,6 +1516,8 @@ dict_load_field_low( byte* index_id, /*!< in/out: index id (8 bytes) an "in" value if index != NULL and "out" if index == NULL */ + bool uncommitted, /*!< in: false=READ COMMITTED, + true=READ UNCOMMITTED */ dict_index_t* index, /*!< in/out: index, could be NULL if we just populate a dict_field_t struct with information from @@ -1585,7 +1609,8 @@ dict_load_field_low( if (!trx_id) { ut_ad(!rec_get_deleted_flag(rec, 0)); - } else if (mtr && trx_sys.find(nullptr, trx_id, false)) { + } else if (!mtr || uncommitted) { + } else if (trx_sys.find(nullptr, trx_id, false)) { const auto savepoint = mtr->get_savepoint(); dict_index_t* sys_field = UT_LIST_GET_FIRST( dict_sys.sys_fields->indexes); @@ -1626,15 +1651,15 @@ dict_load_field_low( return(NULL); } -/********************************************************************//** -Loads definitions for index fields. -@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */ -static -ulint -dict_load_fields( -/*=============*/ - dict_index_t* index, /*!< in/out: index whose fields to load */ - mem_heap_t* heap) /*!< in: memory heap for temporary storage */ +/** +Load definitions for index fields. +@param index index whose fields are to be loaded +@param uncommitted false=READ COMMITTED, true=READ UNCOMMITTED +@param heap memory heap for temporary storage +@return error code +@return DB_SUCCESS if the fields were loaded successfully */ +static dberr_t dict_load_fields(dict_index_t *index, bool uncommitted, + mem_heap_t *heap) { btr_pcur_t pcur; mtr_t mtr; @@ -1669,8 +1694,8 @@ dict_load_fields( for (ulint i = 0; i < index->n_fields; i++) { const char *err_msg = btr_pcur_is_on_user_rec(&pcur) - ? dict_load_field_low(index_id, index, - NULL, NULL, NULL, + ? dict_load_field_low(index_id, uncommitted, index, + nullptr, nullptr, nullptr, heap, &mtr, btr_pcur_get_rec(&pcur)) : dict_load_field_none; @@ -1717,6 +1742,8 @@ dict_load_index_low( byte* table_id, /*!< in/out: table id (8 bytes), an "in" value if mtr and "out" when !mtr */ + bool uncommitted, /*!< in: false=READ COMMITTED, + true=READ UNCOMMITTED */ mem_heap_t* heap, /*!< in/out: temporary memory heap */ const rec_t* rec, /*!< in: SYS_INDEXES record */ mtr_t* mtr, /*!< in/out: mini-transaction, @@ -1798,7 +1825,7 @@ dict_load_index_low( const trx_id_t trx_id = trx_read_trx_id(field); if (!trx_id) { ut_ad(!rec_get_deleted_flag(rec, 0)); - } else if (!mtr) { + } else if (!mtr || uncommitted) { } else if (trx_sys.find(nullptr, trx_id, false)) { const auto savepoint = mtr->get_savepoint(); dict_index_t* sys_index = UT_LIST_GET_FIRST( @@ -1876,20 +1903,18 @@ dict_load_index_low( return(NULL); } -/********************************************************************//** -Loads definitions for table indexes. Adds them to the data dictionary -cache. -@return DB_SUCCESS if ok, DB_CORRUPTION if corruption of dictionary -table or DB_UNSUPPORTED if table has unknown index type */ +/** Load definitions for table indexes. Adds them to the data dictionary cache. +@param table table definition +@param uncommitted false=READ COMMITTED, true=READ UNCOMMITTED +@param heap memory heap for temporary storage +@param ignore_err errors to be ignored when loading the index definition +@return error code +@retval DB_SUCCESS if all indexes were successfully loaded +@retval DB_CORRUPTION if corruption of dictionary table +@retval DB_UNSUPPORTED if table has unknown index type */ static MY_ATTRIBUTE((nonnull)) -dberr_t -dict_load_indexes( -/*==============*/ - dict_table_t* table, /*!< in/out: table */ - mem_heap_t* heap, /*!< in: memory heap for temporary storage */ - dict_err_ignore_t ignore_err) - /*!< in: error to be ignored when - loading the index definition */ +dberr_t dict_load_indexes(dict_table_t *table, bool uncommitted, + mem_heap_t *heap, dict_err_ignore_t ignore_err) { dict_index_t* sys_index; btr_pcur_t pcur; @@ -1952,8 +1977,8 @@ dict_load_indexes( } } - err_msg = dict_load_index_low(table_id, heap, rec, &mtr, table, - &index); + err_msg = dict_load_index_low(table_id, uncommitted, heap, rec, + &mtr, table, &index); ut_ad(!index == !!err_msg); if (err_msg == dict_load_index_none) { @@ -2016,7 +2041,8 @@ dict_load_indexes( } else if (index->page == FIL_NULL && table->is_readable() && (!(index->type & DICT_FTS))) { - if (ignore_err != DICT_ERR_IGNORE_DROP) { + if (!uncommitted + && ignore_err != DICT_ERR_IGNORE_DROP) { ib::error_or_warn(!(ignore_err & DICT_ERR_IGNORE_INDEX)) << "Index " << index->name @@ -2060,7 +2086,10 @@ dict_load_indexes( of the database server */ dict_mem_index_free(index); } else { - dict_load_fields(index, heap); + error = dict_load_fields(index, uncommitted, heap); + if (error != DB_SUCCESS) { + goto func_exit; + } /* The data dictionary tables should never contain invalid index definitions. If we ignored this error @@ -2123,11 +2152,12 @@ dict_load_indexes( /** Load a table definition from a SYS_TABLES record to dict_table_t. Do not load any columns or indexes. @param[in,out] mtr mini-transaction +@param[in] uncommitted whether to use READ UNCOMMITTED isolation level @param[in] rec SYS_TABLES record @param[out,own] table table, or nullptr @return error message @retval nullptr on success */ -const char *dict_load_table_low(mtr_t *mtr, +const char *dict_load_table_low(mtr_t *mtr, bool uncommitted, const rec_t *rec, dict_table_t **table) { table_id_t table_id; @@ -2144,7 +2174,8 @@ const char *dict_load_table_low(mtr_t *mtr, return(error_text); } - if (auto r = dict_sys_tables_rec_read(rec, mtr, &table_id, &space_id, + if (auto r = dict_sys_tables_rec_read(rec, uncommitted, mtr, + &table_id, &space_id, &t_num, &flags, &flags2, &trx_id)) { *table = NULL; @@ -2287,8 +2318,6 @@ static dict_table_t *dict_load_table_one(const span &name, ut_ad(dict_sys.locked()); - mtr.start(); - dict_index_t *sys_index = dict_sys.sys_tables->indexes.start; ut_ad(!dict_sys.sys_tables->not_redundant()); ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, @@ -2312,6 +2341,9 @@ static dict_table_t *dict_load_table_one(const span &name, dfield_set_data(&dfield, name.data(), name.size()); dict_index_copy_types(&tuple, sys_index, 1); + bool uncommitted = false; +reload: + mtr.start(); dberr_t err = btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); @@ -2331,7 +2363,8 @@ static dict_table_t *dict_load_table_one(const span &name, } dict_table_t* table; - if (const char* err_msg = dict_load_table_low(&mtr, rec, &table)) { + if (const char* err_msg = + dict_load_table_low(&mtr, uncommitted, rec, &table)) { if (err_msg != dict_load_table_flags) { ib::error() << err_msg; } @@ -2341,15 +2374,32 @@ static dict_table_t *dict_load_table_one(const span &name, goto err_exit; } + const unsigned use_uncommitted = uncommitted + ? 2 + : table->id == mach_read_from_8( + rec + rec_get_field_start_offs( + rec, DICT_FLD__SYS_TABLES__ID)); + mtr.commit(); mem_heap_t* heap = mem_heap_create(32000); dict_load_tablespace(table, ignore_err); - if (dict_load_columns(table, heap) || dict_load_virtual(table)) { -evict: - dict_sys.remove(table); + switch (dict_load_columns(table, use_uncommitted, heap)) { + case DB_SUCCESS_LOCKED_REC: + ut_ad(!uncommitted); + uncommitted = true; + dict_mem_table_free(table); + mem_heap_free(heap); + goto reload; + case DB_SUCCESS: + if (!dict_load_virtual(table, uncommitted)) { + break; + } + /* fall through */ + default: + dict_mem_table_free(table); mem_heap_free(heap); DBUG_RETURN(nullptr); } @@ -2374,7 +2424,7 @@ static dict_table_t *dict_load_table_one(const span &name, ? DICT_ERR_IGNORE_ALL : ignore_err; - err = dict_load_indexes(table, heap, index_load_err); + err = dict_load_indexes(table, uncommitted, heap, index_load_err); if (err == DB_TABLE_CORRUPT) { /* Refuse to load the table if the table has a corrupted @@ -2382,7 +2432,10 @@ static dict_table_t *dict_load_table_one(const span &name, ut_ad(index_load_err != DICT_ERR_IGNORE_DROP); ib::error() << "Refusing to load corrupted table " << table->name; - goto evict; +evict: + dict_sys.remove(table); + mem_heap_free(heap); + DBUG_RETURN(nullptr); } if (err != DB_SUCCESS || !table->is_readable()) { @@ -2437,14 +2490,12 @@ static dict_table_t *dict_load_table_one(const span &name, changed when dict_load_foreigns() is called below */ table->fk_max_recusive_level = 0; - /* If the force recovery flag is set, we open the table irrespective - of the error condition, since the user may want to dump data from the - clustered index. However we load the foreign key information only if + /* We will load the foreign key information only if all indexes were loaded. */ if (!table->is_readable()) { /* Don't attempt to load the indexes from disk. */ } else if (err == DB_SUCCESS) { - err = dict_load_foreigns(table->name.m_name, nullptr, + err = dict_load_foreigns(table->name.m_name, nullptr, false, 0, true, ignore_err, fk_tables); if (err != DB_SUCCESS) { @@ -2605,7 +2656,7 @@ dict_load_sys_table( heap = mem_heap_create(1000); - dict_load_indexes(table, heap, DICT_ERR_IGNORE_NONE); + dict_load_indexes(table, false, heap, DICT_ERR_IGNORE_NONE); mem_heap_free(heap); } @@ -2775,6 +2826,8 @@ dberr_t dict_load_foreign( /*==============*/ const char* table_name, /*!< in: table name */ + bool uncommitted, /*!< in: use READ UNCOMMITTED + transaction isolation level */ const char** col_names, /*!< in: column names, or NULL to use foreign->foreign_table->col_names */ @@ -2862,7 +2915,8 @@ dict_load_foreign( const trx_id_t tid = trx_read_trx_id(field); - if (tid && tid != trx_id && trx_sys.find(nullptr, tid, false)) { + if (tid && tid != trx_id && !uncommitted + && trx_sys.find(nullptr, tid, false)) { const auto savepoint = mtr.get_savepoint(); rec_offs* offsets = rec_get_offsets( rec, sys_index, nullptr, true, ULINT_UNDEFINED, &heap); @@ -2991,6 +3045,8 @@ dict_load_foreigns( const char* table_name, /*!< in: table name */ const char** col_names, /*!< in: column names, or NULL to use table->col_names */ + bool uncommitted, /*!< in: use READ UNCOMMITTED + transaction isolation level */ trx_id_t trx_id, /*!< in: DDL transaction id, or 0 to check recursive load of tables @@ -3105,7 +3161,7 @@ dict_load_foreigns( /* Load the foreign constraint definition to the dictionary cache */ err = len < sizeof fk_id - ? dict_load_foreign(table_name, col_names, trx_id, + ? dict_load_foreign(table_name, uncommitted, col_names, trx_id, check_recursive, check_charsets, {fk_id, len}, ignore_err, fk_tables) : DB_CORRUPTION; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2dd0859d18160..515f66d6ba32b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -12839,7 +12839,7 @@ int create_table_info_t::create_table(bool create_fk) if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ dict_names_t fk_tables; - err = dict_load_foreigns(m_table_name, nullptr, + err = dict_load_foreigns(m_table_name, nullptr, false, m_trx->id, true, DICT_ERR_IGNORE_NONE, fk_tables); while (err == DB_SUCCESS && !fk_tables.empty()) { diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index fa86a920dd802..f17747be3e3b7 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -9881,7 +9881,7 @@ innobase_update_foreign_cache( dict_names_t fk_tables; err = dict_load_foreigns(user_table->name.m_name, - ctx->col_names, 1, true, + ctx->col_names, false, 1, true, DICT_ERR_IGNORE_NONE, fk_tables); @@ -9892,7 +9892,7 @@ innobase_update_foreign_cache( loaded with "foreign_key checks" off, so let's retry the loading with charset_check is off */ err = dict_load_foreigns(user_table->name.m_name, - ctx->col_names, 1, false, + ctx->col_names, false, 1, false, DICT_ERR_IGNORE_NONE, fk_tables); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 3c67de2f6e54f..dadfa1e2b128f 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -4772,7 +4772,7 @@ static const char *i_s_sys_tables_rec(const btr_pcur_t &pcur, mtr_t *mtr, } if (rec) - return dict_load_table_low(mtr, rec, table); + return dict_load_table_low(mtr, false, rec, table); *table= dict_sys.load_table (span{reinterpret_cast(pcur.old_rec), len}); diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 33095eb8dbcd5..3a64adf923cf9 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -89,6 +89,8 @@ dict_load_foreigns( const char* table_name, /*!< in: table name */ const char** col_names, /*!< in: column names, or NULL to use table->col_names */ + bool uncommitted, /*!< in: use READ UNCOMMITTED + transaction isolation level */ trx_id_t trx_id, /*!< in: DDL transaction id, or 0 to check recursive load of tables @@ -125,11 +127,12 @@ dict_getnext_system( /** Load a table definition from a SYS_TABLES record to dict_table_t. Do not load any columns or indexes. @param[in,out] mtr mini-transaction +@param[in] uncommitted whether to use READ UNCOMMITTED isolation level @param[in] rec SYS_TABLES record @param[out,own] table table, or nullptr @return error message @retval nullptr on success */ -const char *dict_load_table_low(mtr_t *mtr, +const char *dict_load_table_low(mtr_t *mtr, bool uncommitted, const rec_t *rec, dict_table_t **table) MY_ATTRIBUTE((nonnull, warn_unused_result)); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 10fe321a70287..0e982f59545b4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2869,7 +2869,7 @@ row_rename_table_for_mysql( dict_names_t fk_tables; err = dict_load_foreigns( - new_name, nullptr, trx->id, + new_name, nullptr, false, trx->id, !old_is_tmp || trx->check_foreigns, use_fk ? DICT_ERR_IGNORE_NONE From 70021737f541a0cb0732c76d04958b16a47dec49 Mon Sep 17 00:00:00 2001 From: Nayuta Yanagisawa Date: Thu, 8 Sep 2022 21:02:41 +0900 Subject: [PATCH 8/8] MDEV-27172 fixup: spider/bugfix.mdev_27172 failed with --ps-protocol --- storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result | 3 +-- storage/spider/mysql-test/spider/bugfix/t/mdev_27172.test | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result index d4c8c7e8ec294..531e48b880b0e 100644 --- a/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_27172.result @@ -64,12 +64,11 @@ SELECT * FROM tbl_c WHERE greeting = "Aloha!" id greeting 2 Aloha! connection child2_1; -SELECT argument FROM mysql.general_log WHERE argument LIKE 'select %'; +SELECT argument FROM mysql.general_log WHERE argument LIKE 'select `id`,`greeting` from %'; argument select `id`,`greeting` from `auto_test_remote`.`tbl_a` where `greeting` = 'Aloha!' and ((`greeting` = 'Aloha!')) select `id`,`greeting` from `auto_test_remote`.`tbl_b` where `greeting` like 'Aloha%' and ((`greeting` = 'Aloha!')) select `id`,`greeting` from `auto_test_remote`.`tbl_c` where `greeting` like 'Aloha%' and ((`greeting` = 'Aloha!')) -SELECT argument FROM mysql.general_log WHERE argument LIKE 'select %' connection child2_1; SET @@global.general_log = @general_log_backup; SET @@global.log_output = @log_output_backup; diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_27172.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_27172.test index d544a0b400ee3..60c0ad4292116 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/mdev_27172.test +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_27172.test @@ -75,7 +75,7 @@ SELECT * FROM tbl_c WHERE greeting = "Aloha!" AND CASE greeting WHEN "Aloha!" THEN "one" ELSE 'more' END = "one"; # hack to disable GBH --connection child2_1 -SELECT argument FROM mysql.general_log WHERE argument LIKE 'select %'; +SELECT argument FROM mysql.general_log WHERE argument LIKE 'select `id`,`greeting` from %'; --connection child2_1 SET @@global.general_log = @general_log_backup;