From 6831b3f2a0fd656fb41dd9df5f141431988448f1 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 12 Jan 2022 17:18:38 +0300 Subject: [PATCH 1/3] MDEV-26824 Can't add foreign key with empty referenced columns list create_table_info_t::create_foreign_keys() expects equal number of iterations through fk->columns and fk->ref_columns. If fk->ref_columns is empty copy it from fk->columns. --- mysql-test/suite/innodb/r/foreign_key.result | 23 ++++++++++++++++++++ mysql-test/suite/innodb/t/foreign_key.test | 18 +++++++++++++++ sql/sql_table.cc | 18 +++++++++------ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index ff0e025246e..1968661b45a 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -896,4 +896,27 @@ create or replace table t1 (a varchar(4096) unique) engine=innodb; create or replace table t2 (pk int primary key, a varchar(4096) unique, foreign key(a) references t1(a) on update cascade) engine=innodb; ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed") drop table t1; +# +# MDEV-26824 Can't add foreign key with empty referenced columns list +# +create table t2(a int primary key) engine=innodb; +create table t1(a int primary key, b int) engine=innodb; +alter table t2 add foreign key(a) references t1(a, b); +ERROR 42000: Incorrect foreign key definition for 'foreign key without name': Key reference and table reference don't match +create or replace table t1(a tinyint primary key) engine innodb; +alter table t2 add foreign key(a) references t1; +ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed") +create or replace table t1(b int primary key) engine innodb; +alter table t2 add foreign key(a) references t1; +ERROR HY000: Can't create table `test`.`t2` (errno: 150 "Foreign key constraint is incorrectly formed") +create or replace table t1(a int primary key, b int) engine innodb; +alter table t2 add foreign key(a) references t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`), + CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop tables t2, t1; # End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index be248a5bed4..1f25d995827 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -902,6 +902,24 @@ create or replace table t2 (pk int primary key, a varchar(4096) unique, foreign drop table t1; +--echo # +--echo # MDEV-26824 Can't add foreign key with empty referenced columns list +--echo # +create table t2(a int primary key) engine=innodb; +create table t1(a int primary key, b int) engine=innodb; +--error ER_WRONG_FK_DEF +alter table t2 add foreign key(a) references t1(a, b); +create or replace table t1(a tinyint primary key) engine innodb; +--error ER_CANT_CREATE_TABLE +alter table t2 add foreign key(a) references t1; +create or replace table t1(b int primary key) engine innodb; +--error ER_CANT_CREATE_TABLE +alter table t2 add foreign key(a) references t1; +create or replace table t1(a int primary key, b int) engine innodb; +alter table t2 add foreign key(a) references t1; +show create table t2; +drop tables t2, t1; + --echo # End of 10.5 tests --source include/wait_until_count_sessions.inc diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6d8ceb348dc..6956b41bdc5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3809,15 +3809,19 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Foreign_key *fk_key= (Foreign_key*) key; if (fk_key->validate(alter_info->create_list)) DBUG_RETURN(TRUE); - if (fk_key->ref_columns.elements && - fk_key->ref_columns.elements != fk_key->columns.elements) + if (fk_key->ref_columns.elements) { - my_error(ER_WRONG_FK_DEF, MYF(0), - (fk_key->name.str ? fk_key->name.str : - "foreign key without name"), - ER_THD(thd, ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)); - DBUG_RETURN(TRUE); + if (fk_key->ref_columns.elements != fk_key->columns.elements) + { + my_error(ER_WRONG_FK_DEF, MYF(0), + (fk_key->name.str ? fk_key->name.str : + "foreign key without name"), + ER_THD(thd, ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)); + DBUG_RETURN(TRUE); + } } + else + fk_key->ref_columns.append(&fk_key->columns); continue; } (*key_count)++; From e6a06113880fe3842fe7068d42bcae8bb02ab024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 13 Jan 2022 16:45:31 +0200 Subject: [PATCH 2/3] MDEV-27058 fixup: Bogus assertion !block->page.is_io_fixed() buf_page_get_gen(): After recv_sys_t::recover_low() returned, the page must not be read-fixed, but it may be write-fixed, because the io-fix state is protected by block->page.lock, which we are not holding yet. Also, let us copy the block descriptor state to a local variable for examination, so that in case an assertion would fail again, we will have the sampled state in the core dump. In a core dump of the assertion failure, we had block->page.fix() == buf_page_t::UNFIXED, that is, the assertion expression was holding again. --- storage/innobase/buf/buf0buf.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 695637d9d96..11d820be305 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2013, 2021, MariaDB Corporation. +Copyright (c) 2013, 2022, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -2949,9 +2949,12 @@ buf_page_get_gen( { if (buf_block_t *block= recv_sys.recover(page_id)) { - ut_ad(!block->page.is_io_fixed()); /* Recovery is a special case; we fix() before acquiring lock. */ - const auto s= block->page.fix(); + auto s= block->page.fix(); + ut_ad(s >= buf_page_t::FREED); + /* The block may be write-fixed at this point because we are not + holding a lock, but it must not be read-fixed. */ + ut_ad(s < buf_page_t::READ_FIX || s >= buf_page_t::WRITE_FIX); if (err) *err= DB_SUCCESS; const bool must_merge= allow_ibuf_merge && @@ -2963,7 +2966,10 @@ buf_page_get_gen( page_is_leaf(block->page.frame)) { block->page.lock.x_lock(); - if (block->page.is_freed()) + s= block->page.state(); + ut_ad(s > buf_page_t::FREED); + ut_ad(s < buf_page_t::READ_FIX); + if (s < buf_page_t::UNFIXED) ut_ad(mode == BUF_GET_POSSIBLY_FREED || mode == BUF_PEEK_IF_IN_POOL); else { From c104a01b5028d79f9b434a6e0e6748bee405dc67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 14 Jan 2022 17:42:19 +0200 Subject: [PATCH 3/3] MDEV-27500 buf_page_free() fails to drop the adaptive hash index The function buf_page_free() that was introduced in commit a35b4ae89871d8184f04abb112c385481d557dbb (MDEV-15528) failed to remove any adaptive hash index entries for the page before freeing the page. This caused an assertion failure on shutdown of 10.6 server of in the function buf_pool_t::clear_hash_index() with the expression: (s >= buf_page_t::UNFIXED || s == buf_page_t::REMOVE_HASH). The assertion would fail for a block that is in the freed state. The failing assertion was added in commit aaef2e1d8c843d1e40b1ce0c5199c3abb3c5da28 in the 10.6 branch. Thanks to Matthias Leich for finding the bug and testing the fix. --- storage/innobase/buf/buf0buf.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 37f99a94cee..5a49757e857 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2013, 2021, MariaDB Corporation. +Copyright (c) 2013, 2022, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -2500,6 +2500,11 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr, rw_lock_x_lock_inline(&block->lock, 0, file, line); buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); +#ifdef BTR_CUR_HASH_ADAPT + if (block->index) + btr_search_drop_page_hash_index(block); +#endif /* BTR_CUR_HASH_ADAPT */ + block->page.status= buf_page_t::FREED; return; }