[MDEV-25509] Atomic DDL: Assertion `err != DB_DUPLICATE_KEY' fails after previous error upon multi-RENAME Created: 2021-04-24  Updated: 2021-05-10  Resolved: 2021-05-01

Status: Closed
Project: MariaDB Server
Component/s: Server, Storage Engine - InnoDB
Affects Version/s: N/A
Fix Version/s: 10.6.1

Type: Bug Priority: Critical
Reporter: Elena Stepanova Assignee: Thirunarayanan Balathandayuthapani
Resolution: Fixed Votes: 0
Labels: regression

Issue Links:
Relates
relates to MDEV-25642 Assertion `err != DB_DUPLICATE_KEY' f... Closed
relates to MDEV-23632 ALTER TABLE...ADD KEY creates corrupt... Closed

 Description   

--source include/have_innodb.inc
 
SET FOREIGN_KEY_CHECKS= OFF;
CREATE TABLE t1 (pk INT PRIMARY KEY, f INT, FOREIGN KEY (f) REFERENCES t4 (x)) ENGINE=InnoDB;
ALTER TABLE t1 DROP KEY f;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
--error ER_ERROR_ON_RENAME
RENAME TABLE t1 TO t3, t3 TO t4;
RENAME TABLE t2 TO t3;

In the test case above, the second part of the first RENAME query fails with "Foreign key constraint is incorrectly formed", apparently because by dropping the key we've made things so bad that even FOREIGN_KEYS=OFF doesn't help anymore. (Whether it should fail or not is another question, but it was so before atomic DDL and is unrelated to it).

Before atomic DDL it would leave us with t1 renamed to t3, so the next RENAME query would fail with "table already exists".

With the atomic DDL t1 seemingly remains to be t1. But then the 2nd RENAME query fails on the assertion:

bb-10.6-monty with the trigger patch

2021-04-25  0:04:20 4 [ERROR] InnoDB: In RENAME TABLE table `test`.`t4` is referenced in foreign key constraints which are not compatible with the new table definition.
2021-04-25  0:04:20 4 [ERROR] InnoDB: In RENAME TABLE table `test`.`t1` is referenced in foreign key constraints which are not compatible with the new table definition.
mariadbd: /data/src/bb-10.6-monty-patch/storage/innobase/row/row0mysql.cc:4248: dberr_t row_rename_table_for_mysql(const char*, const char*, trx_t*, bool, bool): Assertion `err != DB_DUPLICATE_KEY' failed.
210425  0:04:20 [ERROR] mysqld got signal 6 ;
 
x55b6ffb2a180 "dberr_t row_rename_table_for_mysql(const char*, const char*, trx_t*, bool, bool)") at assert.c:101
#8  0x000055b6fe5bd167 in row_rename_table_for_mysql (old_name=0x7f3585cc4940 "test/t2", new_name=0x7f3585cc4700 "test/t3", trx=0x7f358bc88a90, commit=true, use_fk=true) at /data/src/bb-10.6-monty-patch/storage/innobase/row/row0mysql.cc:4248
#9  0x000055b6fe262877 in innobase_rename_table (trx=0x7f358bc88a90, from=0x7f3585cc5b20 "./test/t2", to=0x7f3585cc5d60 "./test/t3", commit=true) at /data/src/bb-10.6-monty-patch/storage/innobase/handler/ha_innodb.cc:13341
#10 0x000055b6fe22b50e in ha_innobase::rename_table (this=0x62b0000a9580, from=0x7f3585cc5b20 "./test/t2", to=0x7f3585cc5d60 "./test/t3") at /data/src/bb-10.6-monty-patch/storage/innobase/handler/ha_innodb.cc:13534
#11 0x000055b6fd6ffda7 in handler::ha_rename_table (this=0x62b0000a9580, from=0x7f3585cc5b20 "./test/t2", to=0x7f3585cc5d60 "./test/t3") at /data/src/bb-10.6-monty-patch/sql/handler.cc:5025
#12 0x000055b6fd13235c in mysql_rename_table (base=0x616000021d08, old_db=0x62b0000a8400, old_name=0x7f3585cc6b60, new_db=0x62b0000a8b00, new_name=0x7f3585cc6b70, id=0x7f3585cc6b80, flags=0) at /data/src/bb-10.6-monty-patch/sql/sql_table.cc:4941
#13 0x000055b6fcf25a8e in do_rename (thd=0x62b0000d9288, param=0x7f3585cc6b60, ddl_log_state=0x7f3585cc6ca0, ren_table=0x62b0000a83e8, new_db=0x62b0000a8b00, skip_error=false, force_if_exists=0x7f3585cc6c90) at /data/src/bb-10.6-monty-patch/sql/sql_rename.cc:383
#14 0x000055b6fcf2640a in rename_tables (thd=0x62b0000d9288, table_list=0x62b0000a83e8, ddl_log_state=0x7f3585cc6ca0, skip_error=false, if_exists=false, force_if_exists=0x7f3585cc6c90) at /data/src/bb-10.6-monty-patch/sql/sql_rename.cc:533
#15 0x000055b6fcf2436f in mysql_rename_tables (thd=0x62b0000d9288, table_list=0x62b0000a83e8, silent=false, if_exists=false) at /data/src/bb-10.6-monty-patch/sql/sql_rename.cc:164
#16 0x000055b6fceaaf70 in mysql_execute_command (thd=0x62b0000d9288) at /data/src/bb-10.6-monty-patch/sql/sql_parse.cc:4323
#17 0x000055b6fcec57f5 in mysql_parse (thd=0x62b0000d9288, rawbuf=0x62b0000a82a8 "RENAME TABLE t2 TO t3", length=21, parser_state=0x7f3585cc79a0) at /data/src/bb-10.6-monty-patch/sql/sql_parse.cc:8019
#18 0x000055b6fce9b7fd in dispatch_command (command=COM_QUERY, thd=0x62b0000d9288, packet=0x629000294289 "RENAME TABLE t2 TO t3", packet_length=21, blocking=true) at /data/src/bb-10.6-monty-patch/sql/sql_parse.cc:1897
#19 0x000055b6fce9851e in do_command (thd=0x62b0000d9288, blocking=true) at /data/src/bb-10.6-monty-patch/sql/sql_parse.cc:1406
#20 0x000055b6fd2f7d88 in do_handle_one_connection (connect=0x611000021908, put_in_cache=true) at /data/src/bb-10.6-monty-patch/sql/sql_connect.cc:1410
#21 0x000055b6fd2f76e5 in handle_one_connection (arg=0x6110000217c8) at /data/src/bb-10.6-monty-patch/sql/sql_connect.cc:1312
#22 0x000055b6fe007ad1 in pfs_spawn_thread (arg=0x618000007908) at /data/src/bb-10.6-monty-patch/storage/perfschema/pfs.cc:2201
#23 0x00007f359549e609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#24 0x00007f3595072293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Note: I've left the test case without a cleanup, because I don't really know what should happen after the 2nd RENAME, other than that it shouldn't crash. It depends on why exactly the previous foreign key check failed despite foreign key checks being disabled.



 Comments   
Comment by Marko Mäkelä [ 2021-04-25 ]

The assertion was recently added by nikitamalyavin in the 10.3 branch. Later, midenok added a source code comment, referring to MDEV-23632 in the commit message.

Comment by Marko Mäkelä [ 2021-04-25 ]

An error occurs in the error handling of the multi-table RENAME:

#0  dict_foreign_add_to_cache (foreign=foreign@entry=0x7f68a40d7e20, col_names=col_names@entry=0x0, check_charsets=check_charsets@entry=true, ignore_err=ignore_err@entry=DICT_ERR_IGNORE_NONE)
    at /mariadb/bb-10.6-monty/storage/innobase/dict/dict0dict.cc:3122
#1  0x000056545bfc5962 in dict_load_foreign (id=<optimized out>, id@entry=0x7f68b1c10ac0 "test/t1_ibfk_1", col_names=col_names@entry=0x0, check_recursive=check_recursive@entry=false, 
    check_charsets=check_charsets@entry=true, ignore_err=ignore_err@entry=DICT_ERR_IGNORE_NONE, fk_tables=std::deque with 0 elements) at /mariadb/bb-10.6-monty/storage/innobase/dict/dict0load.cc:3155
#2  0x000056545bfc6341 in dict_load_foreigns (table_name=0x7f68b1c116b0 "test/t1", col_names=col_names@entry=0x0, check_recursive=check_recursive@entry=false, check_charsets=true, 
    ignore_err=DICT_ERR_IGNORE_NONE, fk_tables=std::deque with 0 elements) at /mariadb/bb-10.6-monty/storage/innobase/dict/dict0load.cc:3295
#3  0x000056545be3fb09 in row_rename_table_for_mysql (old_name=<optimized out>, old_name@entry=0x7f68b1c118b0 "test/t3", new_name=<optimized out>, new_name@entry=0x7f68b1c116b0 "test/t1", 
    trx=trx@entry=0x7f68c3c01268, commit=commit@entry=true, use_fk=use_fk@entry=true) at /mariadb/bb-10.6-monty/storage/innobase/row/row0mysql.cc:4449
#4  0x000056545bce2ee7 in innobase_rename_table (trx=trx@entry=0x7f68c3c01268, from=from@entry=0x7f68b1c12ba0 "./test/t3", to=to@entry=0x7f68b1c12990 "./test/t1", commit=commit@entry=true)
    at /mariadb/bb-10.6-monty/storage/innobase/handler/ha_innodb.cc:13341
#5  0x000056545bcd4184 in ha_innobase::rename_table (this=<optimized out>, from=0x7f68b1c12ba0 "./test/t3", to=0x7f68b1c12990 "./test/t1") at /mariadb/bb-10.6-monty/storage/innobase/handler/ha_innodb.cc:13534
#6  0x000056545b9875fd in handler::ha_rename_table (this=this@entry=0x7f68a40680f0, from=from@entry=0x7f68b1c12ba0 "./test/t3", to=to@entry=0x7f68b1c12990 "./test/t1")
    at /mariadb/bb-10.6-monty/sql/handler.cc:5025

	if (ref_table && !for_in_cache->referenced_table) {
		index = dict_foreign_find_index(
			ref_table, NULL,
			for_in_cache->referenced_col_names,
			for_in_cache->n_fields, for_in_cache->foreign_index,
			check_charsets, false);
 
		if (index == NULL
		    && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
			dict_foreign_error_report(
				ef, for_in_cache,
				"there is no index in referenced table"
				" which would contain\n"
			DBUG_RETURN(DB_CANNOT_ADD_CONSTRAINT);

The reason why this error was not returned for the initial step RENAME TABLE t1 TO t3 is that for_in_cache->referenced_table was not null at that point of time. The error was returned on the rollback (renaming t3 back to t1).

The fix seems to be more complex than just removing that harmful condition.

Generated at Thu Feb 08 09:38:14 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.