From a26700cca579926cddf9a48c45f13b32785746bb Mon Sep 17 00:00:00 2001 From: Nayuta Yanagisawa Date: Thu, 16 Jun 2022 20:25:02 +0900 Subject: [PATCH 01/17] MDEV-28352 Spider: heap-use-after-free in ha_spider::lock_tables(), heap freed by spider_commit() The heap-use-after-free is caused by the following mechanism: * In the execution of FLUSH TABLE WITH READ LOCK, the function spider_free_trx_conn() is called and the connections held by SPIDER_TRX::trx_conn_hash are freed. * Then, an instance of ha_spider maintains the freed connections because they are also referenced from ha_spider::conns. The ha_spider instance is kept in a lock structure until the corresponding table is unlocked. * Spider accesses ha_spider::conns on the implicit UNLOCK TABLE issued by BEGIN. In the first place, when the connections have been freed, it means that there are really no remote table locked by Spider. Thus, there is no need for Spider to access ha_spider::cons on the implicit UNLOCK TABLE. We can fix the bug by removing the above mentioned access to ha_spider::conns. We also modified spider_free_trx_conn() so that it frees the connections only when no table is locked to reduce the chance of another heap-use-after-free on ha_spider::conns. --- storage/spider/ha_spider.cc | 86 +++++----- .../mysql-test/spider/bugfix/disabled.def | 1 - storage/spider/spd_trx.cc | 151 +++++------------- 3 files changed, 78 insertions(+), 160 deletions(-) diff --git a/storage/spider/ha_spider.cc b/storage/spider/ha_spider.cc index 753d29c23eb..9b3fffcf873 100644 --- a/storage/spider/ha_spider.cc +++ b/storage/spider/ha_spider.cc @@ -1180,10 +1180,8 @@ int ha_spider::external_lock( backup_error_status(); DBUG_ENTER("ha_spider::external_lock"); - DBUG_PRINT("info",("spider this=%p", this)); - DBUG_PRINT("info",("spider lock_type=%x", lock_type)); - DBUG_PRINT("info", ("spider sql_command=%d", thd_sql_command(thd))); + /* Beginning of wide_handler setup */ if (wide_handler->stage == SPD_HND_STAGE_EXTERNAL_LOCK) { /* Only the stage executor deals with table locks. */ @@ -1194,7 +1192,7 @@ int ha_spider::external_lock( } else { - /* Update the stage executor when the stage changes */ + /* Update the stage executor when the stage changes. */ wide_handler->stage= SPD_HND_STAGE_EXTERNAL_LOCK; wide_handler->stage_executor= this; } @@ -1203,35 +1201,30 @@ int ha_spider::external_lock( wide_handler->external_lock_type= lock_type; wide_handler->sql_command = thd_sql_command(thd); - /* We treat BEGIN as if UNLOCK TABLE. */ - if (wide_handler->sql_command == SQLCOM_BEGIN) - { - wide_handler->sql_command = SQLCOM_UNLOCK_TABLES; - } - if (lock_type == F_UNLCK && - wide_handler->sql_command != SQLCOM_UNLOCK_TABLES) - { - DBUG_RETURN(0); - } - - trx = spider_get_trx(thd, TRUE, &error_num); + trx= spider_get_trx(thd, TRUE, &error_num); if (error_num) { DBUG_RETURN(error_num); } - wide_handler->trx = trx; + wide_handler->trx= trx; + /* End of wide_handler setup */ - /* Question: Why the following if block is necessary? Why here? */ if (store_error_num) { DBUG_RETURN(store_error_num); } - DBUG_ASSERT(wide_handler->sql_command != SQLCOM_RENAME_TABLE && - wide_handler->sql_command != SQLCOM_DROP_DB); + /* We treat BEGIN as if UNLOCK TABLE. */ + if (wide_handler->sql_command == SQLCOM_BEGIN) + { + wide_handler->sql_command = SQLCOM_UNLOCK_TABLES; + } + const uint sql_command= wide_handler->sql_command; - if (wide_handler->sql_command == SQLCOM_DROP_TABLE || - wide_handler->sql_command == SQLCOM_ALTER_TABLE) + DBUG_ASSERT(sql_command != SQLCOM_RENAME_TABLE && + sql_command != SQLCOM_DROP_DB); + + if (sql_command == SQLCOM_DROP_TABLE || sql_command == SQLCOM_ALTER_TABLE) { if (trx->locked_connections) { @@ -1242,44 +1235,41 @@ int ha_spider::external_lock( DBUG_RETURN(0); } - if (lock_type != F_UNLCK) + if (lock_type == F_UNLCK) + { + if (sql_command != SQLCOM_UNLOCK_TABLES) + { + DBUG_RETURN(0); /* Unlock remote tables only by UNLOCK TABLES. */ + } + if (!trx->locked_connections) + { + DBUG_RETURN(0); /* No remote table actually locked by Spider */ + } + } + else { if (unlikely((error_num= spider_internal_start_trx(this)))) { DBUG_RETURN(error_num); } - if (wide_handler->sql_command != SQLCOM_SELECT && - wide_handler->sql_command != SQLCOM_HA_READ) + if (sql_command != SQLCOM_SELECT && sql_command != SQLCOM_HA_READ) { trx->updated_in_this_trx= TRUE; - DBUG_PRINT("info", ("spider trx->updated_in_this_trx=TRUE")); + } + if (!wide_handler->lock_table_type) + { + DBUG_RETURN(0); /* No need to actually lock remote tables. */ } } - if (wide_handler->lock_table_type > 0 || - wide_handler->sql_command == SQLCOM_UNLOCK_TABLES) + if (!partition_handler || !partition_handler->handlers) { - if (wide_handler->sql_command == SQLCOM_UNLOCK_TABLES) - { - /* lock tables does not call reset() */ - /* unlock tables does not call store_lock() */ - wide_handler->lock_table_type = 0; - } + DBUG_RETURN(lock_tables()); /* Non-partitioned table */ + } - /* lock/unlock tables */ - if (partition_handler && partition_handler->handlers) - { - for (uint roop_count= 0; roop_count < partition_handler->no_parts; - ++roop_count) - { - if (unlikely((error_num = - partition_handler->handlers[roop_count]->lock_tables()))) - { - DBUG_RETURN(error_num); - } - } - } - else if (unlikely((error_num= lock_tables()))) + for (uint i= 0; i < partition_handler->no_parts; ++i) + { + if (unlikely((error_num= partition_handler->handlers[i]->lock_tables()))) { DBUG_RETURN(error_num); } diff --git a/storage/spider/mysql-test/spider/bugfix/disabled.def b/storage/spider/mysql-test/spider/bugfix/disabled.def index 68de2b6bfde..e19ea07b76b 100644 --- a/storage/spider/mysql-test/spider/bugfix/disabled.def +++ b/storage/spider/mysql-test/spider/bugfix/disabled.def @@ -1,2 +1 @@ wait_timeout : MDEV-26045 -mdev_27239 : failed with ASAN build diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index 80658012506..657d2c3ebe3 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -93,128 +93,51 @@ uchar *spider_trx_ha_get_key( DBUG_RETURN((uchar*) trx_ha->table_name); } -int spider_free_trx_conn( - SPIDER_TRX *trx, - bool trx_free -) { - int roop_count; +/* + Try to free the connections held by the given transaction. +*/ +int spider_free_trx_conn(SPIDER_TRX *trx, bool trx_free) +{ + int loop_count= 0; SPIDER_CONN *conn; + HASH *conn_hash= &trx->trx_conn_hash; + DBUG_ENTER("spider_free_trx_conn"); - roop_count = 0; - if ( - trx_free || - spider_param_conn_recycle_mode(trx->thd) != 2 - ) { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_conn_hash, - roop_count))) + DBUG_ASSERT(!trx_free || !trx->locked_connections); + + /* Clear the connection queues in any case. */ + while ((conn= (SPIDER_CONN *) my_hash_element(conn_hash, loop_count))) + { + spider_conn_clear_queue_at_commit(conn); + loop_count++; + } + + if (trx_free || spider_param_conn_recycle_mode(trx->thd) != 2) + { + /* Free connections only when no connection is locked. */ + if (!trx->locked_connections) { - spider_conn_clear_queue_at_commit(conn); - if (conn->table_lock) + loop_count= 0; + while ((conn= (SPIDER_CONN *) my_hash_element(conn_hash, loop_count))) { - DBUG_ASSERT(!trx_free); - roop_count++; - } else - spider_free_conn_from_trx(trx, conn, FALSE, trx_free, &roop_count); + spider_free_conn_from_trx(trx, conn, FALSE, trx_free, &loop_count); + } } trx->trx_conn_adjustment++; - } else { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_conn_hash, - roop_count))) - { - spider_conn_clear_queue_at_commit(conn); - if (conn->table_lock) - { - DBUG_ASSERT(!trx_free); - } else - conn->error_mode = 1; - roop_count++; - } + + DBUG_RETURN(0); } -#if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) - roop_count = 0; - if ( - trx_free || - spider_param_hs_r_conn_recycle_mode(trx->thd) != 2 - ) { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_hs_r_conn_hash, - roop_count))) - { - if (conn->table_lock) - { - DBUG_ASSERT(!trx_free); - roop_count++; - } else - spider_free_conn_from_trx(trx, conn, FALSE, trx_free, &roop_count); - } - trx->trx_hs_r_conn_adjustment++; - } else { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_hs_r_conn_hash, - roop_count))) - { - if (conn->table_lock) - { - DBUG_ASSERT(!trx_free); - } else - conn->error_mode = 1; - roop_count++; - } - } - roop_count = 0; - if ( - trx_free || - spider_param_hs_w_conn_recycle_mode(trx->thd) != 2 - ) { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_hs_w_conn_hash, - roop_count))) - { - if (conn->table_lock) - { - DBUG_ASSERT(!trx_free); - roop_count++; - } else - spider_free_conn_from_trx(trx, conn, FALSE, trx_free, &roop_count); - } - trx->trx_hs_w_conn_adjustment++; - } else { - while ((conn = (SPIDER_CONN*) my_hash_element(&trx->trx_hs_w_conn_hash, - roop_count))) - { - if (conn->table_lock) - { - DBUG_ASSERT(!trx_free); - } else - conn->error_mode = 1; - roop_count++; - } - } -#endif -#if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) - if (trx_free) + + loop_count= 0; + while ((conn= (SPIDER_CONN *) my_hash_element(conn_hash, loop_count))) { - while ((conn = (SPIDER_CONN*) my_hash_element( - &trx->trx_direct_hs_r_conn_hash, 0))) + if (!conn->table_lock) { -#ifdef HASH_UPDATE_WITH_HASH_VALUE - my_hash_delete_with_hash_value(&trx->trx_direct_hs_r_conn_hash, - conn->conn_key_hash_value, (uchar*) conn); -#else - my_hash_delete(&trx->trx_direct_hs_r_conn_hash, (uchar*) conn); -#endif - spider_free_conn(conn); - } - while ((conn = (SPIDER_CONN*) my_hash_element( - &trx->trx_direct_hs_w_conn_hash, 0))) - { -#ifdef HASH_UPDATE_WITH_HASH_VALUE - my_hash_delete_with_hash_value(&trx->trx_direct_hs_w_conn_hash, - conn->conn_key_hash_value, (uchar*) conn); -#else - my_hash_delete(&trx->trx_direct_hs_w_conn_hash, (uchar*) conn); -#endif - spider_free_conn(conn); + conn->error_mode= 1; } + loop_count++; } -#endif + DBUG_RETURN(0); } @@ -3417,6 +3340,12 @@ int spider_commit( trx->bulk_access_conn_first = NULL; #endif + /* + We do (almost) nothing if the following two conditions are both met: + + * This is just the end of a statement, not an explicit commit. + * The autocommit is OFF or we are in an explicit transaction. + */ if (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { if (trx->trx_start) From 5375f0b495b69dbd6e1d5558ace6ce0fcd9cc636 Mon Sep 17 00:00:00 2001 From: Nayuta Yanagisawa Date: Wed, 22 Jun 2022 00:56:16 +0900 Subject: [PATCH 02/17] MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. The bug is caused by a similar mechanism as MDEV-21027. The function, check_insert_or_replace_autoincrement, failed to open all the partitions on INSERT SELECT statements and it results in the assertion error. --- .../parts/inc/partition_auto_increment.inc | 17 +++++++++++--- .../partition_auto_increment_blackhole.result | 23 +++++++++++++++++++ .../r/partition_auto_increment_innodb.result | 12 ++++++++-- .../r/partition_auto_increment_maria.result | 12 ++++++++-- .../r/partition_auto_increment_memory.result | 12 ++++++++-- .../r/partition_auto_increment_myisam.result | 12 ++++++++-- sql/ha_partition.h | 3 ++- .../r/partition_auto_increment_tokudb.result | 12 ++++++++-- 8 files changed, 89 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/parts/inc/partition_auto_increment.inc b/mysql-test/suite/parts/inc/partition_auto_increment.inc index 2997dd9de4f..fcfd5bce746 100644 --- a/mysql-test/suite/parts/inc/partition_auto_increment.inc +++ b/mysql-test/suite/parts/inc/partition_auto_increment.inc @@ -860,6 +860,8 @@ SELECT LAST_INSERT_ID(); SELECT * FROM t1; DROP TABLE t1; } +--echo ############################################################################## +} if (!$skip_update) { @@ -867,13 +869,13 @@ if (!$skip_update) --echo # MDEV-19622 Assertion failures in --echo # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table --echo # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +eval CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=$engine PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; } -if (!$skip_update) +if (!$skip_delete) { --echo # --echo # MDEV-21027 Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' @@ -884,5 +886,14 @@ REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; } ---echo ############################################################################## +if (!$skip_truncate) +{ +--echo # +--echo # MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +--echo # Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +--echo # +eval CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE=$engine PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; } diff --git a/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result b/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result index 0276385dc29..c017aadcbab 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result @@ -695,3 +695,26 @@ PARTITIONS 2 SELECT * FROM t1 ORDER BY c1; c1 DROP TABLE t1; +# +# MDEV-19622 Assertion failures in +# ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table +# +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='Blackhole' PARTITION BY HASH(a); +INSERT INTO t1 VALUES (1,1),(2,2); +UPDATE t1 SET pk = 0; +DROP TABLE t1; +# +# MDEV-21027 Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' +# ha_partition::set_auto_increment_if_higher +# +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='Blackhole' PARTITION BY HASH (a) PARTITIONS 3; +REPLACE INTO t1 PARTITION (p0) VALUES (3); +DROP TABLE t1; +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='Blackhole' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result index e5414c81616..1b558b619d9 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result @@ -1101,11 +1101,12 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +############################################################################## # # MDEV-19622 Assertion failures in # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='InnoDB' PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; @@ -1116,4 +1117,11 @@ DROP TABLE t1; CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='InnoDB' PARTITION BY HASH (a) PARTITIONS 3; REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; -############################################################################## +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='InnoDB' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/r/partition_auto_increment_maria.result b/mysql-test/suite/parts/r/partition_auto_increment_maria.result index ad041735ebb..8c063958b27 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_maria.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_maria.result @@ -1148,11 +1148,12 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +############################################################################## # # MDEV-19622 Assertion failures in # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='Aria' PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; @@ -1163,4 +1164,11 @@ DROP TABLE t1; CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='Aria' PARTITION BY HASH (a) PARTITIONS 3; REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; -############################################################################## +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='Aria' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/r/partition_auto_increment_memory.result b/mysql-test/suite/parts/r/partition_auto_increment_memory.result index d2d1fb6831c..3461f8b13c5 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_memory.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_memory.result @@ -1129,11 +1129,12 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +############################################################################## # # MDEV-19622 Assertion failures in # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='Memory' PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; @@ -1144,4 +1145,11 @@ DROP TABLE t1; CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='Memory' PARTITION BY HASH (a) PARTITIONS 3; REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; -############################################################################## +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='Memory' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result index f92a6ed18c6..525f47bdbd7 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result @@ -1148,11 +1148,12 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +############################################################################## # # MDEV-19622 Assertion failures in # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='MyISAM' PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; @@ -1163,4 +1164,11 @@ DROP TABLE t1; CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='MyISAM' PARTITION BY HASH (a) PARTITIONS 3; REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; -############################################################################## +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='MyISAM' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 6c0e4ef6cf2..c2a71e143c5 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1408,7 +1408,8 @@ private: unless we already did it. */ if (!part_share->auto_inc_initialized && - (ha_thd()->lex->sql_command == SQLCOM_INSERT || + (ha_thd()->lex->sql_command == SQLCOM_INSERT || + ha_thd()->lex->sql_command == SQLCOM_INSERT_SELECT || ha_thd()->lex->sql_command == SQLCOM_REPLACE) && table->found_next_number_field) bitmap_set_all(&m_part_info->read_partitions); diff --git a/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result b/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result index 9b79cc21875..249a27ce274 100644 --- a/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result +++ b/storage/tokudb/mysql-test/tokudb_parts/r/partition_auto_increment_tokudb.result @@ -1115,11 +1115,12 @@ SELECT * FROM t1; a 0 DROP TABLE t1; +############################################################################## # # MDEV-19622 Assertion failures in # ha_partition::set_auto_increment_if_higher upon UPDATE on Aria table # -CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE=myisam PARTITION BY HASH(a); +CREATE OR REPLACE TABLE t1 (pk INT AUTO_INCREMENT, a INT, KEY(pk)) ENGINE='TokuDB' PARTITION BY HASH(a); INSERT INTO t1 VALUES (1,1),(2,2); UPDATE t1 SET pk = 0; DROP TABLE t1; @@ -1130,5 +1131,12 @@ DROP TABLE t1; CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY) ENGINE='TokuDB' PARTITION BY HASH (a) PARTITIONS 3; REPLACE INTO t1 PARTITION (p0) VALUES (3); DROP TABLE t1; -############################################################################## +# +# MDEV-21310 AUTO_INCREMENT column throws range error on INSERT in partitioned table | +# Assertion `part_share->auto_inc_initialized || !can_use_for_auto_inc_init()' failed. +# +CREATE TABLE t1 (c INT AUTO_INCREMENT KEY) ENGINE='TokuDB' PARTITION BY LIST (c) (PARTITION p1 VALUES IN (1), PARTITION p2 VALUES IN (2)); +ALTER TABLE t1 TRUNCATE PARTITION p1; +INSERT INTO t1 PARTITION (p1) (c) SELECT 1; +DROP TABLE t1; SET GLOBAL tokudb_prelock_empty = @tokudb_prelock_empty_saved; From dbd562787ac652593aacc13eeaa12eb2f06bac24 Mon Sep 17 00:00:00 2001 From: Nayuta Yanagisawa Date: Mon, 11 Oct 2021 14:21:10 +0900 Subject: [PATCH 03/17] MDEV-24343 Spider Left join failed Unknown column 't0.ID' in 'on clause' The Spider mixes the comma join with other join types, and thus ERROR 1054 occurs. This is well-known issue caused by the higher precedence of JOIN over the comma (,). We can fix the problem simply by using JOINs instead of commas. --- .../spider/bugfix/r/mdev_24343.result | 75 +++++++++++++++++ .../mysql-test/spider/bugfix/t/mdev_24343.cnf | 3 + .../spider/bugfix/t/mdev_24343.test | 84 +++++++++++++++++++ .../mysql-test/spider/r/direct_join.result | 2 +- .../spider/r/direct_join_using.result | 2 +- storage/spider/spd_db_mysql.cc | 20 +---- 6 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_24343.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_24343.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_24343.test diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_24343.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_24343.result new file mode 100644 index 00000000000..1d154daa8ec --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_24343.result @@ -0,0 +1,75 @@ +# +# MDEV-24343 Spider Left join failed Unknown column 't0.ID' in 'on clause' +# +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +CREATE TABLE tbl_a ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`first_name` varchar(255) DEFAULT NULL, +PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `tbl_a` VALUES (1,'RICHARD'), (2,'STEPHANE'), (3,'ALAIN'); +CREATE TABLE `tbl_b` ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`last_name` varchar(255) DEFAULT NULL, +PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `tbl_b` VALUES (1,'DEMONGEOT'),(2,'VAROQUI'); +CREATE TABLE `tbl_c` ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`surname` varchar(255) DEFAULT NULL, +PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `tbl_c` VALUES (1,'CON'),(2,'MOYEN'),(3,'MOYEN2'); +SELECT * from tbl_b JOIN tbl_c ON tbl_b.id = tbl_c.id LEFT OUTER JOIN tbl_a ON tbl_a.id = tbl_b.id; +id last_name id surname id first_name +1 DEMONGEOT 1 CON 1 RICHARD +2 VAROQUI 2 MOYEN 2 STEPHANE +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TABLE tbl_a ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`first_name` varchar(255) DEFAULT NULL, +PRIMARY KEY (`id`) +) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_a"' +PARTITION BY LIST COLUMNS(`id`) ( +PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); +CREATE TABLE `tbl_b` ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`last_name` varchar(255) DEFAULT NULL, +PRIMARY KEY (`id`) +) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_b"' +PARTITION BY LIST COLUMNS(`id`) ( +PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); +CREATE TABLE `tbl_c` ( +`id` int(10) unsigned NOT NULL AUTO_INCREMENT, +`surname` varchar(255) DEFAULT NULL, +PRIMARY KEY (`id`) +) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_c"' +PARTITION BY LIST COLUMNS(`id`) ( +PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); +SELECT * from tbl_b JOIN tbl_c ON tbl_b.id = tbl_c.id LEFT OUTER JOIN tbl_a ON tbl_a.id = tbl_b.id; +id last_name id surname id first_name +1 DEMONGEOT 1 CON 1 RICHARD +2 VAROQUI 2 MOYEN 2 STEPHANE +connection master_1; +DROP DATABASE auto_test_local; +connection child2_1; +DROP DATABASE auto_test_remote; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.cnf b/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.test new file mode 100644 index 00000000000..5756cbac993 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_24343.test @@ -0,0 +1,84 @@ +--echo # +--echo # MDEV-24343 Spider Left join failed Unknown column 't0.ID' in 'on clause' +--echo # + +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log + +--connection child2_1 +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +eval CREATE TABLE tbl_a ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `first_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +INSERT INTO `tbl_a` VALUES (1,'RICHARD'), (2,'STEPHANE'), (3,'ALAIN'); + +eval CREATE TABLE `tbl_b` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `last_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`ID`) +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +INSERT INTO `tbl_b` VALUES (1,'DEMONGEOT'),(2,'VAROQUI'); + +eval CREATE TABLE `tbl_c` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `surname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +INSERT INTO `tbl_c` VALUES (1,'CON'),(2,'MOYEN'),(3,'MOYEN2'); + +SELECT * from tbl_b JOIN tbl_c ON tbl_b.id = tbl_c.id LEFT OUTER JOIN tbl_a ON tbl_a.id = tbl_b.id; + +--connection master_1 +CREATE DATABASE auto_test_local; +USE auto_test_local; + +eval CREATE TABLE tbl_a ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `first_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_a"' +PARTITION BY LIST COLUMNS(`id`) ( + PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); + +eval CREATE TABLE `tbl_b` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `last_name` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_b"' +PARTITION BY LIST COLUMNS(`id`) ( + PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); + +eval CREATE TABLE `tbl_c` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `surname` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_c"' +PARTITION BY LIST COLUMNS(`id`) ( + PARTITION `pt1` DEFAULT COMMENT = 'srv "s_2_1"' +); + +SELECT * from tbl_b JOIN tbl_c ON tbl_b.id = tbl_c.id LEFT OUTER JOIN tbl_a ON tbl_a.id = tbl_b.id; + +--connection master_1 +DROP DATABASE auto_test_local; + +--connection child2_1 +DROP DATABASE auto_test_remote; + +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/mysql-test/spider/r/direct_join.result b/storage/spider/mysql-test/spider/r/direct_join.result index a1018c35fbf..36728ad5d45 100644 --- a/storage/spider/mysql-test/spider/r/direct_join.result +++ b/storage/spider/mysql-test/spider/r/direct_join.result @@ -76,7 +76,7 @@ a b c connection child2_1; SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; argument -select t0.`b` `b`,t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0,`auto_test_remote`.`ta_r_3` t1,`auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc limit 1,2 +select t0.`b` `b`,t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc limit 1,2 SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %' SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/mysql-test/spider/r/direct_join_using.result b/storage/spider/mysql-test/spider/r/direct_join_using.result index 66ae1503f9f..93df7b8cd3f 100644 --- a/storage/spider/mysql-test/spider/r/direct_join_using.result +++ b/storage/spider/mysql-test/spider/r/direct_join_using.result @@ -79,7 +79,7 @@ a b c connection child2_1; SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %'; argument -select t0.`b` `b`,t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0,`auto_test_remote`.`ta_r_3` t1,`auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc +select t0.`b` `b`,t0.`a` `a`,t2.`b` `b`,t2.`c` `c` from `auto_test_remote`.`ta_r` t0 join `auto_test_remote`.`ta_r_3` t1 join `auto_test_remote`.`ta_r_int` t2 where ((t0.`a` = t1.`a`) and (t2.`a` = t1.`a`)) order by t0.`b` desc SELECT argument FROM mysql.general_log WHERE argument LIKE '%select %' SELECT a, b, date_format(c, '%Y-%m-%d %H:%i:%s') FROM ta_r ORDER BY a; a b date_format(c, '%Y-%m-%d %H:%i:%s') diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index 782e7efac9d..853e01d60a3 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -7045,25 +7045,13 @@ int spider_db_mbase_util::append_table( } else if (*current_pos > 0 && !first) { DBUG_PRINT("info",("spider no condition")); - if (top_down) + if (str) { - if (str) + if (str->reserve(SPIDER_SQL_JOIN_LEN)) { - if (str->reserve(SPIDER_SQL_JOIN_LEN)) - { - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } - str->q_append(SPIDER_SQL_JOIN_STR, SPIDER_SQL_JOIN_LEN); - } - } else { - if (str) - { - if (str->reserve(SPIDER_SQL_COMMA_LEN)) - { - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } - str->q_append(SPIDER_SQL_COMMA_STR, SPIDER_SQL_COMMA_LEN); + DBUG_RETURN(HA_ERR_OUT_OF_MEM); } + str->q_append(SPIDER_SQL_JOIN_STR, SPIDER_SQL_JOIN_LEN); } } From efdbb3cf31cab1961666a3eb5467680aec2d60f5 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 28 Jun 2022 11:38:27 +0400 Subject: [PATCH 04/17] A cleanup for MDEV-25243 ASAN heap-use-after-free in Item_func_sp::execute_impl upon concurrent view DDL and I_S query with view and function The test was reported to fail sporadicaly with this diff: --- mysql-test/main/information_schema_tables.result +++ mysql-test/main/information_schema_tables.reject @@ -21,6 +21,8 @@ disconnect con1; connection default; DROP VIEW IF EXISTS vv; +Warnings: +Note 4092 Unknown VIEW: 'test.vv' in the "The originally reported non-deterministic test" part. Disabling warnings around the DROP VIEW statement. --- mysql-test/main/information_schema_tables.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/main/information_schema_tables.test b/mysql-test/main/information_schema_tables.test index bc4f269a3fb..ee277276b52 100644 --- a/mysql-test/main/information_schema_tables.test +++ b/mysql-test/main/information_schema_tables.test @@ -37,7 +37,9 @@ SELECT v.* FROM v JOIN INFORMATION_SCHEMA.TABLES WHERE DATA_LENGTH = -1; --eval KILL $conid --disconnect con1 --connection default +--disable_warnings DROP VIEW IF EXISTS vv; +--enable_warnings DROP VIEW v; DROP FUNCTION f; DROP TABLE t; From d89cac0884a5fa0c1c66ebd03757a007b8003a20 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Sat, 18 Jun 2022 02:19:41 +0300 Subject: [PATCH 05/17] MDEV-28567 MDL debug logging Log MDL state transitions. Trace-friendly message format. DBUG_LOCK_FILE replaced by thread-local storage. Logged states legend: Seized lock was acquired without waiting Waiting lock is waiting Acquired lock was acquired after waiting Released lock was released Deadlock lock was aborted due to deadlock Timeout lock was aborted due to timeout >0 Nowait lock was aborted due to zero timeout Killed lock was aborted due to kill message OOM can not acquire because out of memory Usage: mtr --mysqld=--debug=d,mdl,query:i:o,/tmp/mdl.log Cleanup from garbage messages: sed -i -re \ '/(mysql|performance_schema|sys|mtr)\// d; /MDL_BACKUP_/ d' \ /tmp/mdl.log --- sql/mdl.cc | 53 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/sql/mdl.cc b/sql/mdl.cc index 11bd6f6ed16..f67aa2c2de1 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -230,25 +230,32 @@ private: Print a list of all locks to DBUG trace to help with debugging */ +const char *dbug_print_mdl(MDL_ticket *mdl_ticket) +{ + thread_local char buffer[256]; + MDL_key *mdl_key= mdl_ticket->get_key(); + my_snprintf(buffer, sizeof(buffer) - 1, "%.*s/%.*s (%s)", + (int) mdl_key->db_name_length(), mdl_key->db_name(), + (int) mdl_key->name_length(), mdl_key->name(), + mdl_ticket->get_type_name()->str); + return buffer; +} + + static int mdl_dbug_print_lock(MDL_ticket *mdl_ticket, void *arg, bool granted) { String *tmp= (String*) arg; - char buffer[128]; - MDL_key *mdl_key= mdl_ticket->get_key(); - size_t length; - length= my_snprintf(buffer, sizeof(buffer)-1, - "\nname: %s db: %.*s key_name: %.*s (%s)", - mdl_ticket->get_type_name()->str, - (int) mdl_key->db_name_length(), mdl_key->db_name(), - (int) mdl_key->name_length(), mdl_key->name(), - granted ? "granted" : "waiting"); + char buffer[256]; + size_t length= my_snprintf(buffer, sizeof(buffer) - 1, + "\n %s (%s)", dbug_print_mdl(mdl_ticket), + granted ? "granted" : "waiting"); tmp->append(buffer, length); return 0; } const char *mdl_dbug_print_locks() { - static String tmp; + thread_local String tmp; mdl_iterate(mdl_dbug_print_lock, (void*) &tmp); return tmp.c_ptr(); } @@ -2268,13 +2275,19 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) MDL_ticket *ticket; MDL_wait::enum_wait_status wait_status; DBUG_ENTER("MDL_context::acquire_lock"); +#ifndef DBUG_OFF + const char *mdl_lock_name= get_mdl_lock_name( + mdl_request->key.mdl_namespace(), mdl_request->type)->str; +#endif DBUG_PRINT("enter", ("lock_type: %s timeout: %f", - get_mdl_lock_name(mdl_request->key.mdl_namespace(), - mdl_request->type)->str, + mdl_lock_name, lock_wait_timeout)); if (try_acquire_lock_impl(mdl_request, &ticket)) + { + DBUG_PRINT("mdl", ("OOM: %s", mdl_lock_name)); DBUG_RETURN(TRUE); + } if (mdl_request->ticket) { @@ -2284,9 +2297,14 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) accordingly, so we can simply return success. */ DBUG_PRINT("info", ("Got lock without waiting")); + DBUG_PRINT("mdl", ("Seized: %s", dbug_print_mdl(mdl_request->ticket))); DBUG_RETURN(FALSE); } +#ifndef DBUG_OFF + const char *ticket_msg= dbug_print_mdl(ticket); +#endif + /* Our attempt to acquire lock without waiting has failed. As a result of this attempt we got MDL_ticket with m_lock @@ -2297,6 +2315,7 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) if (lock_wait_timeout == 0) { + DBUG_PRINT("mdl", ("Nowait: %s", ticket_msg)); mysql_prlock_unlock(&lock->m_rwlock); MDL_ticket::destroy(ticket); my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); @@ -2335,6 +2354,7 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) mysql_prlock_unlock(&lock->m_rwlock); + DBUG_PRINT("mdl", ("Waiting: %s", ticket_msg)); will_wait_for(ticket); /* There is a shared or exclusive lock on the object. */ @@ -2387,15 +2407,16 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) switch (wait_status) { case MDL_wait::VICTIM: - DBUG_LOCK_FILE; - DBUG_PRINT("mdl_locks", ("%s", mdl_dbug_print_locks())); - DBUG_UNLOCK_FILE; + DBUG_PRINT("mdl", ("Deadlock: %s", ticket_msg)); + DBUG_PRINT("mdl_locks", ("Existing locks:%s", mdl_dbug_print_locks())); my_error(ER_LOCK_DEADLOCK, MYF(0)); break; case MDL_wait::TIMEOUT: + DBUG_PRINT("mdl", ("Timeout: %s", ticket_msg)); my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); break; case MDL_wait::KILLED: + DBUG_PRINT("mdl", ("Killed: %s", ticket_msg)); get_thd()->send_kill_message(); break; default: @@ -2417,6 +2438,7 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) mdl_request->ticket= ticket; + DBUG_PRINT("mdl", ("Acquired: %s", ticket_msg)); DBUG_RETURN(FALSE); } @@ -2845,6 +2867,7 @@ void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket) lock->key.db_name(), lock->key.name())); DBUG_ASSERT(this == ticket->get_ctx()); + DBUG_PRINT("mdl", ("Released: %s", dbug_print_mdl(ticket))); lock->remove_ticket(m_pins, &MDL_lock::m_granted, ticket); From 85c0f4d2de4a0dc6efe36bb16cfe932b90e30a95 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 30 May 2022 16:04:09 +0200 Subject: [PATCH 06/17] C/C 3.3 --- cmake/build_configurations/mysql_release.cmake | 2 ++ libmariadb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/build_configurations/mysql_release.cmake b/cmake/build_configurations/mysql_release.cmake index 7411627685e..3a081073f72 100644 --- a/cmake/build_configurations/mysql_release.cmake +++ b/cmake/build_configurations/mysql_release.cmake @@ -106,6 +106,7 @@ ELSEIF(RPM) SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "") SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "") SET(WITH_PCRE system CACHE STRING "") + SET(CLIENT_PLUGIN_ZSTD OFF) IF(RPM MATCHES "fedora|centos|rhel") SET(WITH_INNODB_BZIP2 OFF CACHE STRING "") SET(WITH_INNODB_LZO OFF CACHE STRING "") @@ -124,6 +125,7 @@ ELSEIF(DEB) SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "") SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "") SET(WITH_PCRE system CACHE STRING "") + SET(CLIENT_PLUGIN_ZSTD OFF) SET(WITH_INNODB_BZIP2 OFF CACHE STRING "") SET(WITH_INNODB_LZMA OFF CACHE STRING "") SET(WITH_INNODB_LZO OFF CACHE STRING "") diff --git a/libmariadb b/libmariadb index ade9bb9c3ef..5e94e7c27ff 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit ade9bb9c3ef5f28a4f076ed3afa455975a8e5ab4 +Subproject commit 5e94e7c27ffad7e76665b1333a67975316b9c3c2 From e34f8781397ed451a84c1a3fdc5766c5b1e28d41 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 7 Jun 2022 18:24:02 +0530 Subject: [PATCH 07/17] MDEV-28706 Redundant InnoDB table fails during alter - Redundant InnoDB table fails to set the flags2 while loading the table. It leads to "Upgrade index name failure" during alter operation. InnoDB should set the flags2 to FTS_AUX_HEX_NAME when fts is being loaded --- .../suite/innodb_fts/r/crash_recovery.result | 12 ++++++++++++ mysql-test/suite/innodb_fts/t/crash_recovery.test | 15 +++++++++++++++ storage/innobase/dict/dict0load.cc | 1 + 3 files changed, 28 insertions(+) diff --git a/mysql-test/suite/innodb_fts/r/crash_recovery.result b/mysql-test/suite/innodb_fts/r/crash_recovery.result index 44d3521df98..0dd092ecfa6 100644 --- a/mysql-test/suite/innodb_fts/r/crash_recovery.result +++ b/mysql-test/suite/innodb_fts/r/crash_recovery.result @@ -134,3 +134,15 @@ id title body 1 MySQL Tutorial DBMS stands for Database... 2 MariaDB Tutorial DB means Database ... DROP TABLE mdev19073, mdev19073_2; +# +# MDEV-28706 Redundant InnoDB table fails during alter +# +SET @@global.innodb_file_per_table = 0; +CREATE TABLE t1 ( +col_int INTEGER, col_text TEXT, +col_text_1 TEXT +) ENGINE = InnoDB ROW_FORMAT = Redundant ; +ALTER TABLE t1 ADD FULLTEXT KEY `ftidx` ( col_text ) ; +INSERT INTO t1 VALUES ( 1255, "mariadb", "InnoDB"); +ALTER TABLE t1 ADD FULLTEXT(col_text_1); +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/crash_recovery.test b/mysql-test/suite/innodb_fts/t/crash_recovery.test index 1b321af236a..0e32608a81a 100644 --- a/mysql-test/suite/innodb_fts/t/crash_recovery.test +++ b/mysql-test/suite/innodb_fts/t/crash_recovery.test @@ -193,3 +193,18 @@ AGAINST ('Database' IN NATURAL LANGUAGE MODE); SELECT * FROM mdev19073_2 WHERE MATCH (title, body) AGAINST ('Database' IN NATURAL LANGUAGE MODE); DROP TABLE mdev19073, mdev19073_2; + +--echo # +--echo # MDEV-28706 Redundant InnoDB table fails during alter +--echo # + +SET @@global.innodb_file_per_table = 0; +CREATE TABLE t1 ( + col_int INTEGER, col_text TEXT, + col_text_1 TEXT +) ENGINE = InnoDB ROW_FORMAT = Redundant ; +ALTER TABLE t1 ADD FULLTEXT KEY `ftidx` ( col_text ) ; +INSERT INTO t1 VALUES ( 1255, "mariadb", "InnoDB"); +--source include/restart_mysqld.inc +ALTER TABLE t1 ADD FULLTEXT(col_text_1); +DROP TABLE t1; diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index dade0c5b19e..b02b480f407 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -1852,6 +1852,7 @@ dict_load_columns( if (table->fts == NULL) { table->fts = fts_create(table); table->fts->cache = fts_cache_create(table); + DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); fts_optimize_add_table(table); } From eb7e24932b7cb190a4b96e5d6d9f9262c68814b3 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 13 Jun 2022 21:32:06 +0530 Subject: [PATCH 08/17] MDEV-28806 Assertion `flag == 1' failure in row_build_index_entry_low upon concurrent ALTER and UPDATE - During online ADD INDEX, InnoDB was incorrectly writing log for an UPDATE that does not affect the being-created index. --- .../suite/gcol/r/innodb_virtual_debug.result | 21 +++++++++++++++ .../suite/gcol/t/innodb_virtual_debug.test | 26 +++++++++++++++++++ storage/innobase/row/row0log.cc | 6 +++++ storage/innobase/row/row0upd.cc | 11 ++++---- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug.result b/mysql-test/suite/gcol/r/innodb_virtual_debug.result index 80b2bde6ca5..9cac55c25e3 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug.result @@ -124,3 +124,24 @@ CHECK TABLE t1; Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; +# +# MDEV-28806 Assertion `flag == 1' failure in +# row_build_index_entry_low upon concurrent ALTER and UPDATE +# +CREATE TABLE t1(a CHAR(8), b INT, c INT AS (b), KEY(a)) ENGINE=InnoDB; +INSERT INTO t1(b) VALUES (1),(2); +connect con1,localhost,root,,test; +SET DEBUG_SYNC="alter_table_inplace_before_lock_upgrade SIGNAL dml_start WAIT_FOR dml_commit"; +ALTER TABLE t1 ADD KEY ind (c); +connection default; +SET DEBUG_SYNC="now WAIT_FOR dml_start"; +UPDATE t1 SET a ='foo'; +SET DEBUG_SYNC="now SIGNAL dml_commit"; +connection con1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +disconnect con1; +connection default; +SET DEBUG_SYNC=RESET; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug.test b/mysql-test/suite/gcol/t/innodb_virtual_debug.test index 5ebc90dac19..cd2b860400c 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug.test @@ -312,4 +312,30 @@ SELECT * FROM t1; CHECK TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-28806 Assertion `flag == 1' failure in +--echo # row_build_index_entry_low upon concurrent ALTER and UPDATE +--echo # + +CREATE TABLE t1(a CHAR(8), b INT, c INT AS (b), KEY(a)) ENGINE=InnoDB; +INSERT INTO t1(b) VALUES (1),(2); + +--connect (con1,localhost,root,,test) +SET DEBUG_SYNC="alter_table_inplace_before_lock_upgrade SIGNAL dml_start WAIT_FOR dml_commit"; +send ALTER TABLE t1 ADD KEY ind (c); + +--connection default +SET DEBUG_SYNC="now WAIT_FOR dml_start"; +UPDATE t1 SET a ='foo'; +SET DEBUG_SYNC="now SIGNAL dml_commit"; + +# Cleanup +--connection con1 +--reap +CHECK TABLE t1; +DROP TABLE t1; +--disconnect con1 +connection default; +SET DEBUG_SYNC=RESET; + --source include/wait_until_count_sessions.inc diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index f2e2511a116..28f0eb42825 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -4061,6 +4061,11 @@ void UndorecApplier::log_update(const dtuple_t &tuple, { if (is_update) { + /* Ignore the index if the update doesn't affect the index */ + if (!row_upd_changes_ord_field_binary(index, update, + nullptr, + row, new_ext)) + goto next_index; dtuple_t *old_entry= row_build_index_entry_low( old_row, old_ext, index, heap, ROW_BUILD_NORMAL); @@ -4080,6 +4085,7 @@ void UndorecApplier::log_update(const dtuple_t &tuple, success= row_log_online_op(index, old_entry, 0); } } +next_index: index->lock.s_unlock(); if (!success) { diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index b53416e2976..a2eacaf8e12 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1261,9 +1261,6 @@ row_upd_changes_ord_field_binary_func( ulint i; const dict_index_t* clust_index; - ut_ad(thr); - ut_ad(thr->graph); - ut_ad(thr->graph->trx); ut_ad(!index->table->skip_alter_undo); n_unique = dict_index_get_n_unique(index); @@ -1463,9 +1460,11 @@ row_upd_changes_ord_field_binary_func( trx_rollback_recovered() when the server had crashed before storing the field. */ - ut_ad(thr->graph->trx->is_recovered); - ut_ad(thr->graph->trx - == trx_roll_crash_recv_trx); + ut_ad(!thr + || thr->graph->trx->is_recovered); + ut_ad(!thr + || thr->graph->trx + == trx_roll_crash_recv_trx); return(TRUE); } From afe607dffa804b3a1153b03e6cdab466bfecd70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 30 Jun 2022 13:00:58 +0300 Subject: [PATCH 09/17] MSAN: Disable some slow tests --- mysql-test/suite/funcs_1/t/myisam_views-big.test | 2 ++ mysql-test/suite/innodb_gis/t/multi_pk.test | 2 ++ mysql-test/suite/innodb_gis/t/rtree_purge.test | 2 ++ 3 files changed, 6 insertions(+) diff --git a/mysql-test/suite/funcs_1/t/myisam_views-big.test b/mysql-test/suite/funcs_1/t/myisam_views-big.test index 21613e78b24..5a5ec42a971 100644 --- a/mysql-test/suite/funcs_1/t/myisam_views-big.test +++ b/mysql-test/suite/funcs_1/t/myisam_views-big.test @@ -4,6 +4,8 @@ # because of a pair of slow Solaris Sparc machines in pb2, # this test is marked as big: --source include/big_test.inc +# This test often times out with MSAN +--source include/not_msan.inc # MyISAM tables should be used # diff --git a/mysql-test/suite/innodb_gis/t/multi_pk.test b/mysql-test/suite/innodb_gis/t/multi_pk.test index c90f794fe15..1be919d165a 100644 --- a/mysql-test/suite/innodb_gis/t/multi_pk.test +++ b/mysql-test/suite/innodb_gis/t/multi_pk.test @@ -8,6 +8,8 @@ --source include/have_debug.inc --source include/big_test.inc --source include/not_valgrind.inc +# This test often times out with MSAN +--source include/not_msan.inc # Create table with R-tree index. create table t1 (c1 int, c2 varchar(255), c3 geometry not null, primary key(c1, c2), spatial index (c3))engine=innodb; diff --git a/mysql-test/suite/innodb_gis/t/rtree_purge.test b/mysql-test/suite/innodb_gis/t/rtree_purge.test index 60ecbe2e53a..fc5ce2e14bc 100644 --- a/mysql-test/suite/innodb_gis/t/rtree_purge.test +++ b/mysql-test/suite/innodb_gis/t/rtree_purge.test @@ -3,6 +3,8 @@ --source include/innodb_page_size.inc --source include/have_sequence.inc --source include/not_valgrind.inc +# This test often times out with MSAN +--source include/not_msan.inc SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; From a1267724cb1d1837026a3a5f49e55931038e43e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 30 Jun 2022 14:28:16 +0300 Subject: [PATCH 10/17] MDEV-26293 InnoDB: Failing assertion: space->is_ready_to_close() ... fil_space_t::acquire_low(): Introduce a parameter that specifies which flags should be avoided. At all times, referenced() must not be incremented if the STOPPING flag is set. When fil_system.mutex is not being held by the current thread, the reference must not be incremented if the CLOSING flag is set (unless NEEDS_FSYNC is set, in fil_space_t::flush()). fil_space_t::acquire(): Invoke acquire_low(STOPPING | CLOSING). In this way, the reference count cannot be incremented after fil_space_t::try_to_close() invoked fil_space_t::set_closing(). If the CLOSING flag was set, we must retry acquire_low() after acquiring fil_system.mutex. fil_space_t::prepare_acquired(): Replaces prepare(true). fil_space_t::acquire_and_prepare(): Replaces prepare(). This basically retries fil_space_t::acquire() after acquiring fil_system.mutex. --- storage/innobase/fil/fil0crypt.cc | 6 +++--- storage/innobase/fil/fil0fil.cc | 20 +++++++++++++------- storage/innobase/include/fil0fil.h | 21 +++++++++++---------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 395dfc8590e..15e427a0ea5 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1,6 +1,6 @@ /***************************************************************************** Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. -Copyright (c) 2014, 2021, MariaDB Corporation. +Copyright (c) 2014, 2022, MariaDB Corporation. 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 the Free Software @@ -1456,7 +1456,7 @@ inline bool fil_space_t::acquire_if_not_stopped() return true; if (UNIV_UNLIKELY(n & STOPPING)) return false; - return UNIV_LIKELY(!(n & CLOSING)) || prepare(true); + return UNIV_LIKELY(!(n & CLOSING)) || prepare_acquired(); } bool fil_crypt_must_default_encrypt() @@ -1567,7 +1567,7 @@ inline fil_space_t *fil_space_t::next(fil_space_t *space, bool recheck, const uint32_t n= space->acquire_low(); if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) break; - if (!(n & STOPPING) && space->prepare(true)) + if (!(n & STOPPING) && space->prepare_acquired()) break; } } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index fcb0b06c1c2..3288b3eee57 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -665,11 +665,9 @@ fil_space_extend_must_retry( } /** @return whether the file is usable for io() */ -ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) +ATTRIBUTE_COLD bool fil_space_t::prepare_acquired() { ut_ad(referenced()); - if (!have_mutex) - mutex_enter(&fil_system.mutex); ut_ad(mutex_own(&fil_system.mutex)); fil_node_t *node= UT_LIST_GET_LAST(chain); ut_ad(!id || purpose == FIL_TYPE_TEMPORARY || @@ -714,8 +712,16 @@ ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) clear: n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); - if (!have_mutex) - mutex_exit(&fil_system.mutex); + return is_open; +} + +/** @return whether the file is usable for io() */ +ATTRIBUTE_COLD bool fil_space_t::acquire_and_prepare() +{ + mutex_enter(&fil_system.mutex); + const auto flags= acquire_low() & (STOPPING | CLOSING); + const bool is_open= !flags || (flags == CLOSING && prepare_acquired()); + mutex_exit(&fil_system.mutex); return is_open; } @@ -1488,13 +1494,13 @@ fil_space_t *fil_space_t::get(ulint id) mutex_enter(&fil_system.mutex); fil_space_t *space= fil_space_get_by_id(id); const uint32_t n= space ? space->acquire_low() : 0; - mutex_exit(&fil_system.mutex); if (n & STOPPING) space= nullptr; - else if ((n & CLOSING) && !space->prepare()) + else if ((n & CLOSING) && !space->prepare_acquired()) space= nullptr; + mutex_exit(&fil_system.mutex); return space; } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 9d5bbcadc65..f2000101b84 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2021, MariaDB Corporation. +Copyright (c) 2013, 2022, MariaDB Corporation. 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 the Free Software @@ -507,15 +507,16 @@ public: private: MY_ATTRIBUTE((warn_unused_result)) - /** Try to acquire a tablespace reference. - @return the old reference count (if STOPPING is set, it was not acquired) */ - uint32_t acquire_low() + /** Try to acquire a tablespace reference (increment referenced()). + @param avoid when these flags are set, nothing will be acquired + @return the old reference count */ + uint32_t acquire_low(uint32_t avoid= STOPPING) { uint32_t n= 0; while (!n_pending.compare_exchange_strong(n, n + 1, std::memory_order_acquire, std::memory_order_relaxed) && - !(n & STOPPING)); + !(n & avoid)); return n; } public: @@ -529,10 +530,8 @@ public: @return whether the file is usable */ bool acquire() { - uint32_t n= acquire_low(); - if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) - return true; - return UNIV_LIKELY(!(n & STOPPING)) && prepare(); + const auto flags= acquire_low(STOPPING | CLOSING) & (STOPPING | CLOSING); + return UNIV_LIKELY(!flags) || (flags == CLOSING && acquire_and_prepare()); } /** Acquire another tablespace reference for I/O. */ @@ -999,7 +998,9 @@ public: private: /** @return whether the file is usable for io() */ - ATTRIBUTE_COLD bool prepare(bool have_mutex= false); + ATTRIBUTE_COLD bool prepare_acquired(); + /** @return whether the file is usable for io() */ + ATTRIBUTE_COLD bool acquire_and_prepare(); #endif /*!UNIV_INNOCHECKSUM */ }; From 99de8cc02878ec8c20bffeaf17443e704d6edbf7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 28 Jun 2022 15:51:05 +0530 Subject: [PATCH 11/17] MDEV-28919 Assertion `(((core_null) + 7) >> 3) == oindex.n_core_null_bytes || !not_redundant()' failed - In case of discarded tablespace, InnoDB can't read the root page to assign the n_core_null_bytes. Consecutive instant DDL fails because of non-matching n_core_null_bytes. --- .../innodb/r/instant_alter_import.result | 26 +++++++++++++++++++ .../suite/innodb/t/instant_alter_import.test | 24 +++++++++++++++++ storage/innobase/handler/handler0alter.cc | 9 +++++++ 3 files changed, 59 insertions(+) diff --git a/mysql-test/suite/innodb/r/instant_alter_import.result b/mysql-test/suite/innodb/r/instant_alter_import.result index fad2fd99685..9a20ed606bd 100644 --- a/mysql-test/suite/innodb/r/instant_alter_import.result +++ b/mysql-test/suite/innodb/r/instant_alter_import.result @@ -127,3 +127,29 @@ UNLOCK TABLES; ALTER TABLE t2 IMPORT TABLESPACE; ERROR HY000: Index for table 't2' is corrupt; try to repair it DROP TABLE t1, t2; +# +# MDEV-28919 Assertion `(((core_null) + 7) >> 3) == +# oindex.n_core_null_bytes || !not_redundant()' failed +# +call mtr.add_suppression(" InnoDB: Tablespace for table `test`.`t` is set as discarded"); +CREATE TABLE t (a INTEGER, b INTEGER as (a) VIRTUAL, +c INTEGER)engine=innodb; +ALTER TABLE t DISCARD TABLESPACE; +ALTER TABLE t DROP COLUMN b, algorithm=instant; +Warnings: +Warning 1814 Tablespace has been discarded for table `t` +ALTER TABLE t DROP COLUMN c, algorithm=instant; +Warnings: +Warning 1814 Tablespace has been discarded for table `t` +CREATE TABLE t1(a INTEGER)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +FLUSH TABLE t1 FOR EXPORT; +unlock tables; +ALTER TABLE t IMPORT tablespace; +check table t; +Table Op Msg_type Msg_text +test.t check status OK +select * from t; +a +1 +DROP TABLE t, t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_import.test b/mysql-test/suite/innodb/t/instant_alter_import.test index fdf9f8e6cd9..7bd5645436c 100644 --- a/mysql-test/suite/innodb/t/instant_alter_import.test +++ b/mysql-test/suite/innodb/t/instant_alter_import.test @@ -203,3 +203,27 @@ UNLOCK TABLES; ALTER TABLE t2 IMPORT TABLESPACE; DROP TABLE t1, t2; + +--echo # +--echo # MDEV-28919 Assertion `(((core_null) + 7) >> 3) == +--echo # oindex.n_core_null_bytes || !not_redundant()' failed +--echo # +call mtr.add_suppression(" InnoDB: Tablespace for table `test`.`t` is set as discarded"); +CREATE TABLE t (a INTEGER, b INTEGER as (a) VIRTUAL, + c INTEGER)engine=innodb; +ALTER TABLE t DISCARD TABLESPACE; +# Table does reload +ALTER TABLE t DROP COLUMN b, algorithm=instant; +ALTER TABLE t DROP COLUMN c, algorithm=instant; + +CREATE TABLE t1(a INTEGER)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +FLUSH TABLE t1 FOR EXPORT; +--let $MYSQLD_DATADIR= `select @@datadir` +--move_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t.cfg +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t.ibd +unlock tables; +ALTER TABLE t IMPORT tablespace; +check table t; +select * from t; +DROP TABLE t, t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 7b92ea85215..5492d6e7c4c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -403,6 +403,15 @@ found_j: goto found_nullable; } } + + /* In case of discarded tablespace, InnoDB can't + read the root page. So assign the null bytes based + on nullabled fields */ + if (!oindex.table->space) { + oindex.n_core_null_bytes= UT_BITS_IN_BYTES( + unsigned(oindex.n_nullable)); + } + /* The n_core_null_bytes only matters for ROW_FORMAT=COMPACT and ROW_FORMAT=DYNAMIC tables. */ ut_ad(UT_BITS_IN_BYTES(core_null) == oindex.n_core_null_bytes From 6dc1bc3a5822007cdb2d5b79f0a37b4d6b9b65c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Jul 2022 09:34:31 +0300 Subject: [PATCH 12/17] Fix clang-15 -Wdeprecated-non-prototype K&R style function definitions are deprecated in all versions of C and not supported in C2x. --- dbug/my_main.c | 4 +--- extra/replace.c | 19 ++++++------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/dbug/my_main.c b/dbug/my_main.c index 2b3e92b53cc..80db4d82e06 100644 --- a/dbug/my_main.c +++ b/dbug/my_main.c @@ -7,9 +7,7 @@ #include #include -int main (argc, argv) -int argc; -char *argv[]; +int main (int argc, char **argv) { register int result, ix; extern int factorial(int); diff --git a/extra/replace.c b/extra/replace.c index 717bc92d0c4..a5c470b0b68 100644 --- a/extra/replace.c +++ b/extra/replace.c @@ -148,9 +148,7 @@ int main(int argc, char *argv[]) /* reads options */ /* Initiates DEBUG - but no debugging here ! */ -static int static_get_options(argc,argv) -register int *argc; -register char **argv[]; +static int static_get_options(int *argc, char***argv) { int help,version; char *pos; @@ -218,10 +216,9 @@ register char **argv[]; } /* static_get_options */ -static int get_replace_strings(argc,argv,from_array,to_array) -register int *argc; -register char **argv[]; -POINTER_ARRAY *from_array,*to_array; +static int get_replace_strings(int *argc, char ***argv, + POINTER_ARRAY *from_array, + POINTER_ARRAY *to_array) { char *pos; @@ -965,9 +962,7 @@ static void free_buffer() bytes read from disk. */ -static int fill_buffer_retaining(fd,n) -File fd; -int n; +static int fill_buffer_retaining(File fd, int n) { int i; @@ -1010,9 +1005,7 @@ int n; /* Return 0 if convert is ok */ /* Global variable update is set if something was changed */ -static int convert_pipe(rep,in,out) -REPLACE *rep; -FILE *in,*out; +static int convert_pipe(REPLACE *rep, FILE *in, FILE *out) { int retain,error; uint length; From 045771c05099cf75fea036fdc89308eb3c06549a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Jul 2022 09:48:36 +0300 Subject: [PATCH 13/17] Fix most clang-15 -Wunused-but-set-variable Also, refactor trx_i_s_common_fill_table() to remove dead code. Warnings about yynerrs in Bison-generated yyparse() will remain for now. --- client/mysql.cc | 9 +- client/mysqlcheck.c | 5 +- client/mysqlslap.c | 12 +- libmariadb | 2 +- scripts/comp_sql.c | 6 +- sql/field.cc | 5 +- sql/ha_partition.cc | 3 - sql/partition_info.cc | 13 +- sql/sql_lex.cc | 2 - sql/sql_statistics.cc | 4 +- sql/sql_table.cc | 3 +- storage/innobase/btr/btr0bulk.cc | 2 - storage/innobase/handler/i_s.cc | 219 +++++++++++------------------- storage/innobase/row/row0merge.cc | 2 - 14 files changed, 98 insertions(+), 189 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index ea92c84e1d1..28311defc81 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2021, MariaDB Corporation. + Copyright (c) 2009, 2022, MariaDB Corporation. 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 @@ -3591,7 +3591,6 @@ print_table_data(MYSQL_RES *result) { String separator(256); MYSQL_ROW cur; - MYSQL_FIELD *field; bool *num_flag; num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); @@ -3603,7 +3602,7 @@ print_table_data(MYSQL_RES *result) mysql_field_seek(result,0); } separator.copy("+",1,charset_info); - while ((field = mysql_fetch_field(result))) + while (MYSQL_FIELD *field= mysql_fetch_field(result)) { uint length= column_names ? field->name_length : 0; if (quick) @@ -3625,7 +3624,7 @@ print_table_data(MYSQL_RES *result) { mysql_field_seek(result,0); (void) tee_fputs("|", PAGER); - for (uint off=0; (field = mysql_fetch_field(result)) ; off++) + while (MYSQL_FIELD *field= mysql_fetch_field(result)) { size_t name_length= (uint) strlen(field->name); size_t numcells= charset_info->cset->numcells(charset_info, @@ -3668,7 +3667,7 @@ print_table_data(MYSQL_RES *result) data_length= (uint) lengths[off]; } - field= mysql_fetch_field(result); + MYSQL_FIELD *field= mysql_fetch_field(result); field_max_length= field->max_length; /* diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index aaf77dbb743..27ccff2a840 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2017, MariaDB + Copyright (c) 2010, 2012, MariaDB 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 @@ -1006,7 +1006,6 @@ static void print_result() char prev[(NAME_LEN+9)*3+2]; char prev_alter[MAX_ALTER_STR_SIZE]; size_t length_of_db= strlen(sock->db); - uint i; my_bool found_error=0, table_rebuild=0; DYNAMIC_ARRAY *array4repair= &tables4repair; DBUG_ENTER("print_result"); @@ -1015,7 +1014,7 @@ static void print_result() prev[0] = '\0'; prev_alter[0]= 0; - for (i = 0; (row = mysql_fetch_row(res)); i++) + while ((row = mysql_fetch_row(res))) { int changed = strcmp(prev, row[0]); my_bool status = !strcmp(row[2], "status"); diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 19544384670..0a3a7cd8582 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2017, MariaDB + Copyright (c) 2010, 2022, MariaDB 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 @@ -1846,12 +1846,11 @@ run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit) pthread_handler_t run_task(void *p) { - ulonglong counter= 0, queries; + ulonglong queries; ulonglong detach_counter; unsigned int commit_counter; MYSQL *mysql; MYSQL_RES *result; - MYSQL_ROW row; statement *ptr; thread_context *con= (thread_context *)p; @@ -1972,8 +1971,7 @@ limit_not_met: my_progname, mysql_errno(mysql), mysql_error(mysql)); else { - while ((row= mysql_fetch_row(result))) - counter++; + while (mysql_fetch_row(result)) {} mysql_free_result(result); } } @@ -1983,7 +1981,7 @@ limit_not_met: if (commit_rate && (++commit_counter == commit_rate)) { commit_counter= 0; - run_query(mysql, "COMMIT", strlen("COMMIT")); + run_query(mysql, C_STRING_WITH_LEN("COMMIT")); } if (con->limit && queries == con->limit) @@ -1995,7 +1993,7 @@ limit_not_met: end: if (commit_rate) - run_query(mysql, "COMMIT", strlen("COMMIT")); + run_query(mysql, C_STRING_WITH_LEN("COMMIT")); mysql_close(mysql); diff --git a/libmariadb b/libmariadb index ab7a81e79e4..d12fd88b6c0 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit ab7a81e79e4be4324a2d09d19d4f5249801ef665 +Subproject commit d12fd88b6c0fafbf25f59e7fecd639cb2b38f157 diff --git a/scripts/comp_sql.c b/scripts/comp_sql.c index 748b2320f2a..abd59e85bb5 100644 --- a/scripts/comp_sql.c +++ b/scripts/comp_sql.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. - Copyright (c) 2012, 2014, Monty Program Ab + Copyright (c) 2012, 2022, MariaDB Corporation. 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 @@ -77,7 +77,6 @@ char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error) static void print_query(FILE *out, const char *query) { const char *ptr= query; - int column= 0; fprintf(out, "\""); while (*ptr) @@ -90,21 +89,18 @@ static void print_query(FILE *out, const char *query) and wrap to the next line, tabulated. */ fprintf(out, "\\n\"\n \""); - column= 2; break; case '\r': /* Skipped */ break; case '\"': fprintf(out, "\\\""); - column++; break; case '\\': fprintf(out, "\\\\"); break; default: putc(*ptr, out); - column++; break; } ptr++; diff --git a/sql/field.cc b/sql/field.cc index 57cf3deed35..3878d261f94 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2021, MariaDB + Copyright (c) 2008, 2022, MariaDB 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 @@ -9990,7 +9990,7 @@ int Field_bit::cmp_prefix(const uchar *a, const uchar *b, size_t prefix_len) } -int Field_bit::key_cmp(const uchar *str, uint length) +int Field_bit::key_cmp(const uchar *str, uint) { if (bit_len) { @@ -9999,7 +9999,6 @@ int Field_bit::key_cmp(const uchar *str, uint length) if ((flag= (int) (bits - *str))) return flag; str++; - length--; } return memcmp(ptr, str, bytes_in_rec); } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5c08c934dde..6d5a54ad8b0 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2353,7 +2353,6 @@ uint ha_partition::del_ren_table(const char *from, const char *to) char *name_buffer_ptr; const char *from_path; const char *to_path= NULL; - uint i; handler **file, **abort_file; DBUG_ENTER("ha_partition::del_ren_table"); @@ -2382,7 +2381,6 @@ uint ha_partition::del_ren_table(const char *from, const char *to) from_path= get_canonical_filename(*file, from, from_lc_buff); if (to != NULL) to_path= get_canonical_filename(*file, to, to_lc_buff); - i= 0; do { if (unlikely((error= create_partition_name(from_buff, sizeof(from_buff), @@ -2407,7 +2405,6 @@ uint ha_partition::del_ren_table(const char *from, const char *to) name_buffer_ptr= strend(name_buffer_ptr) + 1; if (unlikely(error)) save_error= error; - i++; } while (*(++file)); if (to != NULL) { diff --git a/sql/partition_info.cc b/sql/partition_info.cc index cf2536f3969..17a65ad8cd4 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2006, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB Corporation. + Copyright (c) 2010, 2022, MariaDB Corporation. 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 @@ -1583,7 +1583,6 @@ bool partition_info::set_up_charset_field_preps(THD *thd) uchar **char_ptrs; unsigned i; size_t size; - uint tot_fields= 0; uint tot_part_fields= 0; uint tot_subpart_fields= 0; DBUG_ENTER("set_up_charset_field_preps"); @@ -1595,13 +1594,8 @@ bool partition_info::set_up_charset_field_preps(THD *thd) ptr= part_field_array; /* Set up arrays and buffers for those fields */ while ((field= *(ptr++))) - { if (field_is_partition_charset(field)) - { tot_part_fields++; - tot_fields++; - } - } size= tot_part_fields * sizeof(char*); if (!(char_ptrs= (uchar**)thd->calloc(size))) goto error; @@ -1635,13 +1629,8 @@ bool partition_info::set_up_charset_field_preps(THD *thd) /* Set up arrays and buffers for those fields */ ptr= subpart_field_array; while ((field= *(ptr++))) - { if (field_is_partition_charset(field)) - { tot_subpart_fields++; - tot_fields++; - } - } size= tot_subpart_fields * sizeof(char*); if (!(char_ptrs= (uchar**) thd->calloc(size))) goto error; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5a00518b806..e4c5b7cbd75 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2191,7 +2191,6 @@ int Lex_input_stream::scan_ident_delimited(THD *thd, Lex_ident_cli_st *str) { CHARSET_INFO *const cs= thd->charset(); - uint double_quotes= 0; uchar c, quote_char= m_tok_start[0]; DBUG_ASSERT(m_ptr == m_tok_start + 1); @@ -2216,7 +2215,6 @@ int Lex_input_stream::scan_ident_delimited(THD *thd, if (yyPeek() != quote_char) break; c= yyGet(); - double_quotes++; continue; } } diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 721b2de75a3..5e31034847e 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1,5 +1,5 @@ /* Copyright (C) 2009 MySQL AB - Copyright (c) 2019, 2020, MariaDB Corporation. + Copyright (c) 2019, 2022, MariaDB Corporation. 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 @@ -2483,7 +2483,6 @@ int collect_statistics_for_index(THD *thd, TABLE *table, uint index) { int rc= 0; KEY *key_info= &table->key_info[index]; - ha_rows rows= 0; DBUG_ENTER("collect_statistics_for_index"); @@ -2518,7 +2517,6 @@ int collect_statistics_for_index(THD *thd, TABLE *table, uint index) if (rc) break; - rows++; index_prefix_calc.add(); rc= table->file->ha_index_next(table->record[0]); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 62b9cb22df0..cc9cb37ca15 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3633,7 +3633,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, List_iterator key_iterator(alter_info->key_list); List_iterator key_iterator2(alter_info->key_list); - uint key_parts=0, fk_key_count=0; + uint key_parts=0; bool primary_key=0,unique_key=0; Key *key, *key2; uint tmp, key_number; @@ -3649,7 +3649,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, "(none)" , key->type)); if (key->type == Key::FOREIGN_KEY) { - fk_key_count++; Foreign_key *fk_key= (Foreign_key*) key; if (fk_key->validate(alter_info->create_list)) DBUG_RETURN(TRUE); diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index c05cf2a7b7a..fdeba1e375b 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -301,7 +301,6 @@ PageBulk::finish() #endif ulint count = 0; - ulint n_recs = 0; ulint slot_index = 0; rec_t* insert_rec = page_rec_get_next(page_get_infimum_rec(m_page)); page_dir_slot_t* slot = NULL; @@ -309,7 +308,6 @@ PageBulk::finish() /* Set owner & dir. */ while (!page_rec_is_supremum(insert_rec)) { count++; - n_recs++; if (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2) { diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index ff0bb9b9129..20297ce1d61 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -59,6 +59,7 @@ Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits) #include "fil0crypt.h" #include "dict0crea.h" #include "fts0vlc.h" +#include "log.h" /** The latest successfully looked up innodb_fts_aux_table */ UNIV_INTERN table_id_t innodb_ft_aux_table_id; @@ -190,19 +191,37 @@ sync_arr_fill_sys_semphore_waits_table( TABLE_LIST* tables, /*!< in/out: tables to fill */ Item* ); /*!< in: condition (not used) */ -/*******************************************************************//** +/** Common function to fill any of the dynamic tables: INFORMATION_SCHEMA.innodb_trx INFORMATION_SCHEMA.innodb_locks INFORMATION_SCHEMA.innodb_lock_waits -@return 0 on success */ -static -int -trx_i_s_common_fill_table( -/*======================*/ - THD* thd, /*!< in: thread */ - TABLE_LIST* tables, /*!< in/out: tables to fill */ - Item* ); /*!< in: condition (not used) */ +@retval false if access to the table is blocked +@retval true if something should be filled in */ +static bool trx_i_s_common_fill_table(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("trx_i_s_common_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) + DBUG_RETURN(false); + + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); + + /* update the cache */ + trx_i_s_cache_start_write(trx_i_s_cache); + trx_i_s_possibly_fetch_data_into_cache(trx_i_s_cache); + trx_i_s_cache_end_write(trx_i_s_cache); + + if (trx_i_s_cache_is_truncated(trx_i_s_cache)) + sql_print_warning("InnoDB: Data in %.*s truncated due to memory limit" + " of %u bytes", + int(tables->schema_table_name.length), + tables->schema_table_name.str, + TRX_I_S_MEM_LIMIT); + + DBUG_RETURN(true); +} /*******************************************************************//** Unbind a dynamic INFORMATION_SCHEMA table. @@ -394,26 +413,29 @@ static ST_FIELD_INFO innodb_trx_fields_info[]= /*******************************************************************//** Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx table with it. -@return 0 on success */ -static -int -fill_innodb_trx_from_cache( -/*=======================*/ - trx_i_s_cache_t* cache, /*!< in: cache to read from */ - THD* thd, /*!< in: used to call - schema_table_store_record() */ - TABLE* table) /*!< in/out: fill this table */ +@retval 0 on success +@retval 1 on failure */ +static int fill_innodb_trx_from_cache(THD *thd, TABLE_LIST *tables, Item*) { - Field** fields; ulint rows_num; char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1]; ulint i; DBUG_ENTER("fill_innodb_trx_from_cache"); - fields = table->field; + if (!trx_i_s_common_fill_table(thd, tables)) { + DBUG_RETURN(0); + } - rows_num = trx_i_s_cache_get_rows_used(cache, + struct cache + { + cache() { trx_i_s_cache_start_read(trx_i_s_cache); } + ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + } c; + + Field** fields = tables->table->field; + + rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_TRX); for (i = 0; i < rows_num; i++) { @@ -423,7 +445,7 @@ fill_innodb_trx_from_cache( row = (i_s_trx_row_t*) trx_i_s_cache_get_nth_row( - cache, I_S_INNODB_TRX, i); + trx_i_s_cache, I_S_INNODB_TRX, i); /* trx_id */ snprintf(trx_id, sizeof(trx_id), TRX_ID_FMT, row->trx_id); @@ -535,7 +557,7 @@ fill_innodb_trx_from_cache( (longlong) row->trx_is_autocommit_non_locking, true)); - OK(schema_table_store_record(thd, table)); + OK(schema_table_store_record(thd, tables->table)); } DBUG_RETURN(0); @@ -557,7 +579,7 @@ innodb_trx_init( schema = (ST_SCHEMA_TABLE*) p; schema->fields_info = innodb_trx_fields_info; - schema->fill_table = trx_i_s_common_fill_table; + schema->fill_table = fill_innodb_trx_from_cache; DBUG_RETURN(0); } @@ -672,20 +694,29 @@ static int fill_innodb_locks_from_cache( /*=========================*/ - trx_i_s_cache_t* cache, /*!< in: cache to read from */ THD* thd, /*!< in: MySQL client connection */ - TABLE* table) /*!< in/out: fill this table */ + TABLE_LIST* tables, /*!< in/out: fill this table */ + Item*) { - Field** fields; ulint rows_num; char lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1]; ulint i; DBUG_ENTER("fill_innodb_locks_from_cache"); - fields = table->field; + if (!trx_i_s_common_fill_table(thd, tables)) { + DBUG_RETURN(0); + } - rows_num = trx_i_s_cache_get_rows_used(cache, + struct cache + { + cache() { trx_i_s_cache_start_read(trx_i_s_cache); } + ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + } c; + + Field** fields = tables->table->field; + + rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_LOCKS); for (i = 0; i < rows_num; i++) { @@ -698,7 +729,7 @@ fill_innodb_locks_from_cache( row = (i_s_locks_row_t*) trx_i_s_cache_get_nth_row( - cache, I_S_INNODB_LOCKS, i); + trx_i_s_cache, I_S_INNODB_LOCKS, i); /* lock_id */ trx_i_s_create_lock_id(row, lock_id, sizeof(lock_id)); @@ -746,7 +777,7 @@ fill_innodb_locks_from_cache( OK(field_store_string(fields[IDX_LOCK_DATA], row->lock_data)); - OK(schema_table_store_record(thd, table)); + OK(schema_table_store_record(thd, tables->table)); } DBUG_RETURN(0); @@ -768,7 +799,7 @@ innodb_locks_init( schema = (ST_SCHEMA_TABLE*) p; schema->fields_info = innodb_locks_fields_info; - schema->fill_table = trx_i_s_common_fill_table; + schema->fill_table = fill_innodb_locks_from_cache; DBUG_RETURN(0); } @@ -852,12 +883,11 @@ static int fill_innodb_lock_waits_from_cache( /*==============================*/ - trx_i_s_cache_t* cache, /*!< in: cache to read from */ THD* thd, /*!< in: used to call schema_table_store_record() */ - TABLE* table) /*!< in/out: fill this table */ + TABLE_LIST* tables, /*!< in/out: fill this table */ + Item*) { - Field** fields; ulint rows_num; char requested_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1]; char blocking_lock_id[TRX_I_S_LOCK_ID_MAX_LEN + 1]; @@ -865,9 +895,19 @@ fill_innodb_lock_waits_from_cache( DBUG_ENTER("fill_innodb_lock_waits_from_cache"); - fields = table->field; + if (!trx_i_s_common_fill_table(thd, tables)) { + DBUG_RETURN(0); + } - rows_num = trx_i_s_cache_get_rows_used(cache, + struct cache + { + cache() { trx_i_s_cache_start_read(trx_i_s_cache); } + ~cache() { trx_i_s_cache_end_read(trx_i_s_cache); } + } c; + + Field** fields = tables->table->field; + + rows_num = trx_i_s_cache_get_rows_used(trx_i_s_cache, I_S_INNODB_LOCK_WAITS); for (i = 0; i < rows_num; i++) { @@ -879,7 +919,7 @@ fill_innodb_lock_waits_from_cache( row = (i_s_lock_waits_row_t*) trx_i_s_cache_get_nth_row( - cache, I_S_INNODB_LOCK_WAITS, i); + trx_i_s_cache, I_S_INNODB_LOCK_WAITS, i); /* requesting_trx_id */ snprintf(requesting_trx_id, sizeof(requesting_trx_id), @@ -909,7 +949,7 @@ fill_innodb_lock_waits_from_cache( blocking_lock_id, sizeof(blocking_lock_id)))); - OK(schema_table_store_record(thd, table)); + OK(schema_table_store_record(thd, tables->table)); } DBUG_RETURN(0); @@ -931,7 +971,7 @@ innodb_lock_waits_init( schema = (ST_SCHEMA_TABLE*) p; schema->fields_info = innodb_lock_waits_fields_info; - schema->fill_table = trx_i_s_common_fill_table; + schema->fill_table = fill_innodb_lock_waits_from_cache; DBUG_RETURN(0); } @@ -985,105 +1025,6 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_lock_waits = MariaDB_PLUGIN_MATURITY_STABLE, }; -/*******************************************************************//** -Common function to fill any of the dynamic tables: -INFORMATION_SCHEMA.innodb_trx -INFORMATION_SCHEMA.innodb_locks -INFORMATION_SCHEMA.innodb_lock_waits -@return 0 on success */ -static -int -trx_i_s_common_fill_table( -/*======================*/ - THD* thd, /*!< in: thread */ - TABLE_LIST* tables, /*!< in/out: tables to fill */ - Item* ) /*!< in: condition (not used) */ -{ - LEX_CSTRING table_name; - int ret; - trx_i_s_cache_t* cache; - - DBUG_ENTER("trx_i_s_common_fill_table"); - - /* deny access to non-superusers */ - if (check_global_access(thd, PROCESS_ACL)) { - - DBUG_RETURN(0); - } - - /* minimize the number of places where global variables are - referenced */ - cache = trx_i_s_cache; - - /* which table we have to fill? */ - table_name = tables->schema_table_name; - /* or table_name = tables->schema_table->table_name; */ - - RETURN_IF_INNODB_NOT_STARTED(table_name.str); - - /* update the cache */ - trx_i_s_cache_start_write(cache); - trx_i_s_possibly_fetch_data_into_cache(cache); - trx_i_s_cache_end_write(cache); - - if (trx_i_s_cache_is_truncated(cache)) { - - ib::warn() << "Data in " << table_name.str << " truncated due to" - " memory limit of " << TRX_I_S_MEM_LIMIT << " bytes"; - } - - ret = 0; - - trx_i_s_cache_start_read(cache); - - if (innobase_strcasecmp(table_name.str, "innodb_trx") == 0) { - - if (fill_innodb_trx_from_cache( - cache, thd, tables->table) != 0) { - - ret = 1; - } - - } else if (innobase_strcasecmp(table_name.str, "innodb_locks") == 0) { - - if (fill_innodb_locks_from_cache( - cache, thd, tables->table) != 0) { - - ret = 1; - } - - } else if (innobase_strcasecmp(table_name.str, "innodb_lock_waits") == 0) { - - if (fill_innodb_lock_waits_from_cache( - cache, thd, tables->table) != 0) { - - ret = 1; - } - - } else { - ib::error() << "trx_i_s_common_fill_table() was" - " called to fill unknown table: " << table_name.str << "." - " This function only knows how to fill" - " innodb_trx, innodb_locks and" - " innodb_lock_waits tables."; - - ret = 1; - } - - trx_i_s_cache_end_read(cache); - -#if 0 - DBUG_RETURN(ret); -#else - /* if this function returns something else than 0 then a - deadlock occurs between the mysqld server and mysql client, - see http://bugs.mysql.com/29900 ; when that bug is resolved - we can enable the DBUG_RETURN(ret) above */ - ret++; // silence a gcc46 warning - DBUG_RETURN(0); -#endif -} - /* Fields of the dynamic table information_schema.innodb_cmp. */ static ST_FIELD_INFO i_s_cmp_fields_info[]= { diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 71df96c5be1..cb2f10b5546 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -126,7 +126,6 @@ public: rec_offs* ins_offsets = NULL; dberr_t error = DB_SUCCESS; dtuple_t* dtuple; - ulint count = 0; const ulint flag = BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG; @@ -234,7 +233,6 @@ public: mtr_commit(&mtr); rtr_clean_rtr_info(&rtr_info, true); - count++; } m_dtuple_vec->clear(); From 7c35ad16e39591a044fe08cb692888a7f6502847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Jul 2022 13:02:43 +0300 Subject: [PATCH 14/17] MDEV-28389 fixup: Fix pre-GCC 10 -Wconversion Before version 10, GCC would think that a right shift of an unsigned char returns int. Let us explicitly cast that back, to silence a bogus -Wconversion warning. --- storage/innobase/buf/buf0buf.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 6a859f3293a..90d0011b675 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1247,7 +1247,10 @@ void buf_page_print(const byte *read_buf, const page_size_t &page_size) byte row[64]; for (byte *r= row; r != &row[64]; r+= 2, read_buf++) - r[0]= hex_to_ascii(*read_buf >> 4), r[1]= hex_to_ascii(*read_buf & 15); + { + r[0]= hex_to_ascii(byte(*read_buf >> 4)); + r[1]= hex_to_ascii(*read_buf & 15); + } sql_print_information("InnoDB: %.*s", 64, row); } From 990cde800a4aafc5f5647eb06db3eec461fd172a Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 1 Jul 2022 14:00:57 +0530 Subject: [PATCH 15/17] MDEV-28912 NON-UNIQUE FTS_DOC_ID index mistaken as FTS_DOC_ID_INDEX - InnoDB mistakenly identifies the non-unique FTS_DOC_ID index as FTS_DOC_ID_INDEX while loading the table. dict_load_indexes() should check whether the index is unique before assigning fts_doc_id_index --- mysql-test/suite/innodb_fts/r/fulltext2.result | 7 +++++++ mysql-test/suite/innodb_fts/t/fulltext2.test | 11 +++++++++++ storage/innobase/dict/dict0load.cc | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_fts/r/fulltext2.result b/mysql-test/suite/innodb_fts/r/fulltext2.result index 8f8135b35cd..e9a089ab80d 100644 --- a/mysql-test/suite/innodb_fts/r/fulltext2.result +++ b/mysql-test/suite/innodb_fts/r/fulltext2.result @@ -271,3 +271,10 @@ fts_doc_id first_name last_name score 6 Ned Flanders 0 7 Nelson Muntz 0 DROP TABLE t1; +CREATE TABLE t1(a INT, b TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL, +KEY FTS_DOC_ID_INDEX(FTS_DOC_ID))ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN c INT as (a) VIRTUAL; +ALTER TABLE t1 ADD d INT NULL; +ALTER TABLE t1 ADD FULLTEXT(b); +ERROR HY000: Index 'FTS_DOC_ID_INDEX' is of wrong type for an InnoDB FULLTEXT index +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/fulltext2.test b/mysql-test/suite/innodb_fts/t/fulltext2.test index 4dd2c78827f..1e3894644a0 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext2.test +++ b/mysql-test/suite/innodb_fts/t/fulltext2.test @@ -257,3 +257,14 @@ INSERT INTO t1 (id, first_name, last_name) VALUES analyze table t1; SELECT fts_doc_id, first_name, last_name, MATCH(first_name) AGAINST('Homer' IN BOOLEAN MODE) AS score FROM t1; DROP TABLE t1; + +# +# MDEV-28912 NON-UNIQUE FTS_DOC_ID mistaken as FTS_DOC_ID_INDEX +# +CREATE TABLE t1(a INT, b TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL, + KEY FTS_DOC_ID_INDEX(FTS_DOC_ID))ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN c INT as (a) VIRTUAL; +ALTER TABLE t1 ADD d INT NULL; +--error ER_INNODB_FT_WRONG_DOCID_INDEX +ALTER TABLE t1 ADD FULLTEXT(b); +DROP TABLE t1; diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index b02b480f407..6b34b89b4f4 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2590,8 +2590,11 @@ next_rec: ut_ad(table->fts_doc_id_index == NULL); if (table->fts != NULL) { - table->fts_doc_id_index = dict_table_get_index_on_name( + dict_index_t *idx = dict_table_get_index_on_name( table, FTS_DOC_ID_INDEX_NAME); + if (idx && dict_index_is_unique(idx)) { + table->fts_doc_id_index = idx; + } } /* If the table contains FTS indexes, populate table->fts->indexes */ From ba3354fca61fa0ee6c3dc614e7ef1be79a4038ef Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 1 Jul 2022 13:04:44 +0200 Subject: [PATCH 16/17] MDEV-28995 Sporadic Assertion on shutdown in threadpool_winsockets.cc Remove the affected assert. Wait for all AIO_buffer_cache::release_buffer() to finish before AIO_buffer_cache::clear(). --- sql/threadpool_winsockets.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sql/threadpool_winsockets.cc b/sql/threadpool_winsockets.cc index 41167781283..a214cda2a5c 100644 --- a/sql/threadpool_winsockets.cc +++ b/sql/threadpool_winsockets.cc @@ -114,8 +114,17 @@ void AIO_buffer_cache::clear() if (!m_base) return; - /* Check that all items are returned to the cache. */ - DBUG_ASSERT(m_cache.size() == m_elements); + std::unique_lock lk(m_mtx, std::defer_lock); + for(;;) + { + if (lk.try_lock()) + { + if (m_cache.size() == m_elements) + break; + lk.unlock(); + } + Sleep(100); + } VirtualFree(m_base, 0, MEM_RELEASE); m_cache.clear(); m_base= 0; From b546913ba2f17be8cc2c0d009c09082663edd703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Jul 2022 14:42:13 +0300 Subject: [PATCH 17/17] Valgrind: Disable tests that would often time out Starting with 10.5, InnoDB crash recovery tests seem to time out more easily under Valgrind, which emulates multiple threads by interleaving them in a single operating system thread. These tests will still be covered by AddressSanitizer and MemorySanitizer. --- mysql-test/suite/innodb/t/alter_copy.test | 3 +-- mysql-test/suite/innodb/t/blob-crash.test | 1 + mysql-test/suite/innodb/t/log_file_name_debug.test | 1 + mysql-test/suite/innodb/t/read_only_recover_committed.test | 1 + mysql-test/suite/innodb/t/table_flags.test | 1 + mysql-test/suite/innodb/t/xa_recovery.test | 1 + mysql-test/suite/multi_source/multi_parallel.test | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/t/alter_copy.test b/mysql-test/suite/innodb/t/alter_copy.test index de2f99b68d4..e67f6f9a66b 100644 --- a/mysql-test/suite/innodb/t/alter_copy.test +++ b/mysql-test/suite/innodb/t/alter_copy.test @@ -2,8 +2,7 @@ --source include/have_debug.inc --source include/have_debug_sync.inc --source include/not_embedded.inc -# Valgrind gives leaks from the first shutdown which confuses mtr -#--source include/not_valgrind.inc +--source include/no_valgrind_without_big.inc --echo # --echo # MDEV-11415 AVOID INTERMEDIATE COMMIT WHILE DOING diff --git a/mysql-test/suite/innodb/t/blob-crash.test b/mysql-test/suite/innodb/t/blob-crash.test index beb500553ea..5d529059742 100644 --- a/mysql-test/suite/innodb/t/blob-crash.test +++ b/mysql-test/suite/innodb/t/blob-crash.test @@ -1,5 +1,6 @@ --source include/maybe_debug.inc --source include/innodb_page_size_small.inc +--source include/no_valgrind_without_big.inc --echo # --echo # Bug #16963396 INNODB: USE OF LARGE EXTERNALLY-STORED FIELDS MAKES diff --git a/mysql-test/suite/innodb/t/log_file_name_debug.test b/mysql-test/suite/innodb/t/log_file_name_debug.test index d90be6d8916..239606b121b 100644 --- a/mysql-test/suite/innodb/t/log_file_name_debug.test +++ b/mysql-test/suite/innodb/t/log_file_name_debug.test @@ -2,6 +2,7 @@ # Embedded server does not support restarting --source include/not_embedded.inc --source include/have_debug.inc +--source include/no_valgrind_without_big.inc --echo # --echo # Bug#19685095 DO NOT CARE ABOUT UNRESOLVED MLOG_FILE_NAME diff --git a/mysql-test/suite/innodb/t/read_only_recover_committed.test b/mysql-test/suite/innodb/t/read_only_recover_committed.test index 439f57e9fad..d309f359aaa 100644 --- a/mysql-test/suite/innodb/t/read_only_recover_committed.test +++ b/mysql-test/suite/innodb/t/read_only_recover_committed.test @@ -3,6 +3,7 @@ --source include/have_debug_sync.inc # need to restart server --source include/not_embedded.inc +--source include/no_valgrind_without_big.inc --disable_query_log # Ignore messages from the innodb_force_recovery=5 startup. diff --git a/mysql-test/suite/innodb/t/table_flags.test b/mysql-test/suite/innodb/t/table_flags.test index 79b2c3dd77a..4003f7cdf27 100644 --- a/mysql-test/suite/innodb/t/table_flags.test +++ b/mysql-test/suite/innodb/t/table_flags.test @@ -2,6 +2,7 @@ # Embedded server tests do not support restarting --source include/not_embedded.inc --source include/maybe_debug.inc +--source include/no_valgrind_without_big.inc --disable_query_log call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found"); diff --git a/mysql-test/suite/innodb/t/xa_recovery.test b/mysql-test/suite/innodb/t/xa_recovery.test index bb8e3316860..f0fbb1a94c3 100644 --- a/mysql-test/suite/innodb/t/xa_recovery.test +++ b/mysql-test/suite/innodb/t/xa_recovery.test @@ -1,6 +1,7 @@ --source include/have_innodb.inc # Embedded server does not support restarting. --source include/not_embedded.inc +--source include/no_valgrind_without_big.inc # MDEV-8841 - close tables opened by previous tests, # so they don't get marked crashed when the server gets crashed diff --git a/mysql-test/suite/multi_source/multi_parallel.test b/mysql-test/suite/multi_source/multi_parallel.test index a1385198b61..2bbb344378c 100644 --- a/mysql-test/suite/multi_source/multi_parallel.test +++ b/mysql-test/suite/multi_source/multi_parallel.test @@ -2,6 +2,7 @@ # Slave_non_transactional_groups, Slave_transactional_groups --source include/not_embedded.inc --source include/have_innodb.inc +--source include/no_valgrind_without_big.inc --let $rpl_server_count= 0 --connect (master1,127.0.0.1,root,,,$SERVER_MYPORT_1)