diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 49365b6e9be9a..230097f47c781 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -263,7 +263,6 @@ a b vb 4 NULL NULL 5 NULL NULL DROP TABLE t1; -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; # # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col # @@ -282,3 +281,21 @@ connection default; SET DEBUG_SYNC='RESET'; disconnect con2; DROP TABLE t1; +# +# MDEV-24653 Assertion block->page.id.page_no() == index->page failed +# in innobase_add_instant_try() +# +SET @saved_limit = @@GLOBAL.innodb_limit_optimistic_insert_debug; +SET GLOBAL innodb_limit_optimistic_insert_debug = 2; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3),(4); +ALTER TABLE t1 ADD COLUMN b INT; +DELETE FROM t1; +InnoDB 0 transactions not purged +ALTER TABLE t1 ADD COLUMN c INT; +SELECT * FROM t1; +a b c +DROP TABLE t1; +SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit; +# End of 10.3 tests +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index cec7a05725b82..d3aea85b243ec 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -292,8 +292,6 @@ CHECK TABLE t1; SELECT * FROM t1; DROP TABLE t1; -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; - --echo # --echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col --echo # @@ -319,3 +317,26 @@ SET DEBUG_SYNC='now SIGNAL update'; SET DEBUG_SYNC='RESET'; --disconnect con2 DROP TABLE t1; + +--echo # +--echo # MDEV-24653 Assertion block->page.id.page_no() == index->page failed +--echo # in innobase_add_instant_try() +--echo # + +SET @saved_limit = @@GLOBAL.innodb_limit_optimistic_insert_debug; +SET GLOBAL innodb_limit_optimistic_insert_debug = 2; + +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3),(4); +ALTER TABLE t1 ADD COLUMN b INT; +DELETE FROM t1; +--source include/wait_all_purged.inc +ALTER TABLE t1 ADD COLUMN c INT; + +SELECT * FROM t1; +DROP TABLE t1; +SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit; + +--echo # End of 10.3 tests + +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 019369d997dcb..8faa6c626ff6f 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2021, 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 @@ -128,13 +128,14 @@ btr_pcur_store_position( cursor->old_stored = true; if (page_is_empty(block->frame)) { + ut_ad(block->page.id.page_no() == index->page); +empty_table: /* It must be an empty index tree; NOTE that in this case we do not store the modify_clock, but always do a search if we restore the cursor position */ ut_a(!page_has_siblings(block->frame)); ut_ad(page_is_leaf(block->frame)); - ut_ad(block->page.id.page_no() == index->page); if (page_rec_is_supremum_low(offs)) { cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; @@ -150,7 +151,15 @@ btr_pcur_store_position( rec = page_rec_get_prev(rec); ut_ad(!page_rec_is_infimum(rec)); - ut_ad(!rec_is_metadata(rec, index)); + + if (UNIV_UNLIKELY(rec_is_metadata(rec, index))) { + /* The table may be empty such that it only + contains a metadata record, in a leaf page + that is not the root page. */ + ut_ad(index->is_primary()); + ut_ad(block->page.id.page_no() != index->page); + goto empty_table; + } cursor->rel_pos = BTR_PCUR_AFTER; } else if (page_rec_is_infimum_low(offs)) { @@ -160,7 +169,9 @@ btr_pcur_store_position( ut_ad(!page_has_prev(block->frame)); rec = page_rec_get_next(rec); if (page_rec_is_supremum(rec)) { - ut_ad(page_has_next(block->frame)); + ut_ad(page_has_next(block->frame) + || block->page.id.page_no() + != index->page); goto before_first; } } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 574b29a261e92..6d4e545248a4f 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, 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 @@ -4482,11 +4482,13 @@ innobase_add_instant_try( const rec_t* rec = btr_pcur_get_rec(&pcur); que_thr_t* thr = pars_complete_graph_for_exec( NULL, trx, ctx->heap, NULL); + const bool is_root = block->page.id.page_no() == index->page; dberr_t err; if (rec_is_metadata(rec, index)) { ut_ad(page_rec_is_user_rec(rec)); - if (!page_has_next(block->frame) + if (is_root + && !page_has_next(block->frame) && page_rec_is_last(rec, block->frame)) { goto empty_table; } @@ -4528,7 +4530,7 @@ innobase_add_instant_try( } btr_pcur_close(&pcur); goto func_exit; - } else if (page_rec_is_supremum(rec)) { + } else if (is_root && page_rec_is_supremum(rec)) { empty_table: /* The table is empty. */ ut_ad(fil_page_index_page_check(block->frame));