From a72f34c0a240c2dca920041c0c0c1e8a9119a0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 9 Aug 2017 15:21:42 +0300 Subject: [PATCH] MDEV-12868 MySQL bug #84038 also affects MariaDB 10.2 Cherry-pick the commit from MySQL 5.7.19, and adapt the test case: commit 45c933ac19c73a3e9c756a87ee1ba18ba1ac564c Author: Aakanksha Verma Date: Tue Mar 21 10:31:43 2017 +0530 Bug #25189192 ERRORS WHEN RESTARTING MYSQL AFTER RENAME TABLE. PROBLEM While renaming table innodb doesn't update the InnoDB Dictionary table INNODB_SYS_DATAFILES incase there is change in database while doing rename table. Hence on a restart the server log shows error that it couldnt find table with old path before rename which has actually been renamed. So the errors would only vanish if we update the system tablespace FIX Update the innodb dictionary table with new path in the case there is not a change in the table but the database holding the table as well. Reviewed-by: Jimmy Yang RB: 15751 --- mysql-test/suite/innodb/r/rename_table.result | 20 ++++++++++++ mysql-test/suite/innodb/t/rename_table.opt | 2 ++ mysql-test/suite/innodb/t/rename_table.test | 31 +++++++++++++++++++ storage/innobase/row/row0mysql.cc | 10 ++++++ 4 files changed, 63 insertions(+) create mode 100644 mysql-test/suite/innodb/r/rename_table.result create mode 100644 mysql-test/suite/innodb/t/rename_table.opt create mode 100644 mysql-test/suite/innodb/t/rename_table.test diff --git a/mysql-test/suite/innodb/r/rename_table.result b/mysql-test/suite/innodb/r/rename_table.result new file mode 100644 index 00000000000..3d7c3ff1b0e --- /dev/null +++ b/mysql-test/suite/innodb/r/rename_table.result @@ -0,0 +1,20 @@ +CREATE DATABASE test_jfg; +CREATE DATABASE test_jfg2; +CREATE TABLE test_jfg.test (a int unsigned PRIMARY KEY) ENGINE=InnoDB; +RENAME TABLE test_jfg.test TO test_jfg2.test; +SELECT REPLACE(path,'\\','/') path +FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES WHERE PATH LIKE '%test%'; +path +./test_jfg2/test.ibd +DROP DATABASE test_jfg; +DROP DATABASE test_jfg2; +CREATE DATABASE abc_def; +CREATE DATABASE abc_def2; +CREATE TABLE abc_def.test (a int unsigned PRIMARY KEY) ENGINE=InnoDB; +RENAME TABLE abc_def.test TO abc_def2.test1; +SELECT REPLACE(path,'\\','/') path +FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES WHERE PATH LIKE '%test%'; +path +./abc_def2/test1.ibd +DROP DATABASE abc_def; +DROP DATABASE abc_def2; diff --git a/mysql-test/suite/innodb/t/rename_table.opt b/mysql-test/suite/innodb/t/rename_table.opt new file mode 100644 index 00000000000..a4c52ea7d79 --- /dev/null +++ b/mysql-test/suite/innodb/t/rename_table.opt @@ -0,0 +1,2 @@ +--innodb +--innodb-sys-datafiles diff --git a/mysql-test/suite/innodb/t/rename_table.test b/mysql-test/suite/innodb/t/rename_table.test new file mode 100644 index 00000000000..ea9f70bacb0 --- /dev/null +++ b/mysql-test/suite/innodb/t/rename_table.test @@ -0,0 +1,31 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc + +CREATE DATABASE test_jfg; +CREATE DATABASE test_jfg2; +CREATE TABLE test_jfg.test (a int unsigned PRIMARY KEY) ENGINE=InnoDB; +RENAME TABLE test_jfg.test TO test_jfg2.test; + +SELECT REPLACE(path,'\\','/') path +FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES WHERE PATH LIKE '%test%'; + +DROP DATABASE test_jfg; + +--source include/restart_mysqld.inc + +DROP DATABASE test_jfg2; + +CREATE DATABASE abc_def; +CREATE DATABASE abc_def2; + +CREATE TABLE abc_def.test (a int unsigned PRIMARY KEY) ENGINE=InnoDB; +RENAME TABLE abc_def.test TO abc_def2.test1; + +SELECT REPLACE(path,'\\','/') path +FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES WHERE PATH LIKE '%test%'; + +DROP DATABASE abc_def; + +--source include/restart_mysqld.inc + +DROP DATABASE abc_def2; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index e7ecca307cc..720140e572e 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -4595,6 +4595,15 @@ row_rename_table_for_mysql( && dict_table_is_file_per_table(table)) { /* Make a new pathname to update SYS_DATAFILES. */ char* new_path = row_make_new_pathname(table, new_name); + char* old_path = fil_space_get_first_path(table->space); + + /* If old path and new path are the same means tablename + has not changed and only the database name holding the table + has changed so we need to make the complete filepath again. */ + if (!dict_tables_have_same_db(old_name, new_name)) { + ut_free(new_path); + new_path = fil_make_filepath(NULL, new_name, IBD, false); + } info = pars_info_create(); @@ -4614,6 +4623,7 @@ row_rename_table_for_mysql( "END;\n" , FALSE, trx); + ut_free(old_path); ut_free(new_path); } if (err != DB_SUCCESS) {