diff --git a/mysql-test/main/create_or_replace.result b/mysql-test/main/create_or_replace.result index d3b3a8d4f36..31a3d549472 100644 --- a/mysql-test/main/create_or_replace.result +++ b/mysql-test/main/create_or_replace.result @@ -891,3 +891,24 @@ select * from information_schema.innodb_sys_foreign; ID FOR_NAME REF_NAME N_COLS TYPE select * from information_schema.innodb_sys_foreign_cols; ID FOR_COL_NAME REF_COL_NAME POS +# +# MDEV-29544 SIGSEGV in HA_CREATE_INFO::finalize_locked_tables +# +call mtr.add_suppression("mysql.innodb_index_stats"); +set sql_mode= ''; +create table t (x int) engine innodb; +insert into t values (77); +alter table mysql.innodb_index_stats modify stat_description char(10); +Warnings: +Warning 1265 Data truncated for column 'stat_description' at row 2 +Warning 1265 Data truncated for column 'stat_description' at row 3 +lock table t write; +create or replace table t (y int); +ERROR HY000: Error on rename of './test/t' to './test/#sql-backup-t' (errno: 168 "Unknown (generic) error from engine") +unlock tables; +alter table mysql.innodb_index_stats modify stat_description varchar(1024) not null; +select * from t; +x +77 +drop table t; +set sql_mode= default; diff --git a/mysql-test/main/create_or_replace.test b/mysql-test/main/create_or_replace.test index c5dc01de84f..205355911e8 100644 --- a/mysql-test/main/create_or_replace.test +++ b/mysql-test/main/create_or_replace.test @@ -677,3 +677,23 @@ select * from information_schema.innodb_sys_foreign_cols; drop tables u, t; select * from information_schema.innodb_sys_foreign; select * from information_schema.innodb_sys_foreign_cols; + +--echo # +--echo # MDEV-29544 SIGSEGV in HA_CREATE_INFO::finalize_locked_tables +--echo # +call mtr.add_suppression("mysql.innodb_index_stats"); +set sql_mode= ''; +create table t (x int) engine innodb; +insert into t values (77); +alter table mysql.innodb_index_stats modify stat_description char(10); +lock table t write; +--replace_regex /#sql-backup-.+-.+-/#sql-backup-/ +--replace_result $MYSQLD_DATADIR ./ +--error ER_ERROR_ON_RENAME +create or replace table t (y int); +# cleanup +unlock tables; +alter table mysql.innodb_index_stats modify stat_description varchar(1024) not null; +select * from t; +drop table t; +set sql_mode= default; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 13168e9cec8..de71432a355 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4398,6 +4398,7 @@ bool HA_CREATE_INFO::finalize_atomic_replace(THD *thd, TABLE_LIST *orig_table) LEX_CSTRING cpath; char path[FN_REFLEN + 1]; cpath.str= path; + bool locked_tables_decremented= false; DBUG_ASSERT(is_atomic_replace()); @@ -4435,11 +4436,15 @@ bool HA_CREATE_INFO::finalize_atomic_replace(THD *thd, TABLE_LIST *orig_table) DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db.str, table_name.str, MDL_EXCLUSIVE)); - + /* + HA_EXTRA_PREPARE_FOR_DROP: after CREATE OR REPLACE table + must be not locked, removing it from thd->locked_tables_list. + */ close_all_tables_for_name(thd, table->s, HA_EXTRA_PREPARE_FOR_DROP, NULL); table= NULL; orig_table->table= NULL; + locked_tables_decremented= true; } param.rename_flags= FN_TO_IS_TMP; @@ -4450,7 +4455,11 @@ bool HA_CREATE_INFO::finalize_atomic_replace(THD *thd, TABLE_LIST *orig_table) param.new_alias= backup_name.table_name; if (rename_table_and_triggers(thd, ¶m, NULL, orig_table, &backup_name.db, false, &dummy)) + { + if (locked_tables_decremented) + thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); return true; + } debug_crash_here("ddl_log_create_after_save_backup"); } @@ -4465,7 +4474,11 @@ bool HA_CREATE_INFO::finalize_atomic_replace(THD *thd, TABLE_LIST *orig_table) &cpath, &db, &table_name, false) || rename_table_and_triggers(thd, ¶m, NULL, &tmp_name, &db, false, &dummy)) + { + if (locked_tables_decremented) + thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); return true; + } debug_crash_here("ddl_log_create_after_install_new"); return false; }