#At file:///home2/mydev/bzrroot/mysql-6.0-bug42572-2/ based on
revid:charles.bell@stripped
2815 Ingo Struewing 2009-05-19
Bug#42572 - Restore fails when myisampack used with -b option
The use of myisampack -b creates a table backup file in the
database directory. On DROP DATABASE, this file is not
noticed as belonging to a database object. It is not deleted.
DROP DATABASE fails because the directory is not empty.
The same situation exists if the user creates files in the
database directory, which are not known to MySQL as belonging
to database objects. For example backup image files.
RESTORE ignored the failing DROP DATABASE. It failed when a
CREATE DATABASE for the not dropped database failed.
The problem is solved by renaming the non-empty database
directory, if DROP DATABASE fails due to unknown files.
@ mysql-test/suite/backup/r/backup_external.result
Bug#42572 - Restore fails when myisampack used with -b option
Updated test result.
@ mysql-test/suite/backup/t/backup_external.test
Bug#42572 - Restore fails when myisampack used with -b option
Fixed test.
@ sql/share/errmsg.txt
Bug#42572 - Restore fails when myisampack used with -b option
Added ER_RESTORE_RENAME.
@ sql/si_objects.cc
Bug#42572 - Restore fails when myisampack used with -b option
Added Abstract_obj::m_errno.
Added Database_obj::drop()
modified:
mysql-test/suite/backup/r/backup_external.result
mysql-test/suite/backup/t/backup_external.test
sql/share/errmsg.txt
sql/si_objects.cc
=== modified file 'mysql-test/suite/backup/r/backup_external.result'
--- a/mysql-test/suite/backup/r/backup_external.result 2009-03-25 22:17:35 +0000
+++ b/mysql-test/suite/backup/r/backup_external.result 2009-05-19 09:28:51 +0000
@@ -257,18 +257,21 @@ id name
3 test3
4 test4
+#
+# Bug#42572 - Restore fails when myisampack used with -b option
+#
# Use myisampack -b option to make backup of table datafile
BACKUP DATABASE db1 TO 'db1b.bak';
backup_id
#
RESTORE FROM 'db1b.bak' OVERWRITE;
-ERROR HY000: Could not restore database `db1`
-SHOW TABLES FROM db1;
-Tables_in_db1
-# Perform restore again to get the tables from db1 back
-RESTORE FROM 'db1.bak' OVERWRITE;
backup_id
#
+Warnings:
+# # Renamed directory with unknown files to 'db1-#'
+SHOW TABLES FROM db1;
+Tables_in_db1
+t1
# Check data contents and indexes in table
SHOW TABLES FROM db1;
Tables_in_db1
=== modified file 'mysql-test/suite/backup/t/backup_external.test'
--- a/mysql-test/suite/backup/t/backup_external.test 2009-03-25 22:17:35 +0000
+++ b/mysql-test/suite/backup/t/backup_external.test 2009-05-19 09:28:51 +0000
@@ -149,6 +149,9 @@ SELECT COUNT(*) FROM db1.t1 WHERE id < 5
SELECT * FROM db1.t1 LIMIT 4;
--echo
+--echo #
+--echo # Bug#42572 - Restore fails when myisampack used with -b option
+--echo #
--echo # Use myisampack -b option to make backup of table datafile
--exec $MYISAMCHK -s --unpack $MYSQLD_DATADIR/db1/t1.MYI
@@ -160,20 +163,19 @@ SELECT * FROM db1.t1 LIMIT 4;
BACKUP DATABASE db1 TO 'db1b.bak';
# Perform restore
---replace_column 1 #
---error ER_BACKUP_CANT_RESTORE_DB
+# Mask UUID and path delimiter.
+--replace_regex /db1-[^']*/db1-#/ /'\.[\/\\]/'/
+# Mask backup_id and warning numbers.
+--replace_column 1 # 2 #
RESTORE FROM 'db1b.bak' OVERWRITE;
-SHOW TABLES FROM db1;
-# No tables will be seen in db1. This is because of Bug#42572. Once this bug is
-# fixed, restore should pass and tables should be present in db1.
+# Get rid of the directory, saved by RESTORE.
+let $warn = query_get_value(SHOW WARNINGS, Message, 1);
+let $dir = `SELECT SUBSTR("$warn", INSTR("$warn", "db1-"), 40)`;
+--remove_file $MYSQLD_DATADIR/$dir/t1.OLD
+--rmdir $MYSQLD_DATADIR/$dir
-# Remove the .OLD file from database directory
---exec rm $MYSQLD_DATADIR/db1/t1.OLD
-
---echo # Perform restore again to get the tables from db1 back
---replace_column 1 #
-RESTORE FROM 'db1.bak' OVERWRITE;
+SHOW TABLES FROM db1;
--echo # Check data contents and indexes in table
SHOW TABLES FROM db1;
=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt 2009-05-14 16:52:22 +0000
+++ b/sql/share/errmsg.txt 2009-05-19 09:28:51 +0000
@@ -6516,3 +6516,5 @@ ER_BACKUP_INTERRUPTED
eng "Operation has been interrupted."
ER_BACKUP_NOT_ENABLED
eng "The MySQL Backup system is disabled in this release. Use --new on server startup
to enable."
+ER_RESTORE_RENAME
+ eng "Renamed directory with unknown files to '%.200s'"
=== modified file 'sql/si_objects.cc'
--- a/sql/si_objects.cc 2009-05-05 17:42:58 +0000
+++ b/sql/si_objects.cc 2009-05-19 09:28:51 +0000
@@ -606,6 +606,7 @@ protected:
protected:
MEM_ROOT m_mem_root; /* This mem-root is for keeping stmt list. */
List<LEX_STRING> m_stmt_list;
+ int m_errno; //< Remember last error number of last statement
protected:
/* These attributes are to be used only for serialization. */
@@ -649,6 +650,7 @@ inline Abstract_obj::Abstract_obj(LEX_ST
m_id.copy(id.str, id.length, system_charset_info);
else
m_id.length(0);
+ m_errno= 0;
}
///////////////////////////////////////////////////////////////////////////
@@ -797,6 +799,10 @@ bool Abstract_obj::drop(THD *thd)
/* Execute DDL operation. */
rc= ed_connection.execute_direct(*sql_text);
+ /* Save error number. Ed_connection gets destroyed on return. */
+ if (rc)
+ m_errno= ed_connection.get_last_errno();
+
/* Disable further DDL execution. */
::obs::bml_exception_off(thd);
@@ -861,6 +867,7 @@ public:
public:
virtual inline const String *get_db_name() const { return get_name(); }
+ virtual bool drop(THD *thd);
private:
virtual bool do_serialize(THD *thd, Out_stream &out_stream);
@@ -1767,6 +1774,81 @@ void Database_obj::build_drop_statement(
}
///////////////////////////////////////////////////////////////////////////
+
+/**
+ Drop the database.
+
+ @param[in] thd Server thread context.
+
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE on error.
+*/
+
+bool Database_obj::drop(THD *thd)
+{
+ bool rc;
+ DBUG_ENTER("Database_obj::drop");
+
+ /*
+ If DROP DATABASE fails due to unknown files in the directory,
+ fix that by renaming the directory.
+ */
+ rc= Abstract_obj::drop(thd);
+ if (rc)
+ {
+ DBUG_PRINT("si_objects", ("drop database failed, m_errno: %d", m_errno));
+ if (m_errno == ER_DB_DROP_RMDIR)
+ {
+ size_t len= get_name()->length();
+ char oldname[FN_REFLEN];
+ char newname[FN_REFLEN];
+ uchar uuid[MY_UUID_SIZE];
+
+ DBUG_PRINT("si_objects", ("Renaming to oldname-uuid"));
+ /*
+ get_name() returns a const String. We cannot use c_ptr*() with it.
+ New name is ./dbname-UUID
+ */
+ if (len + 3 + MY_UUID_STRING_LENGTH >= FN_REFLEN)
+ goto err; /* purecov: inspected */
+ memcpy(oldname, get_name()->ptr(), len);
+ oldname[len] = '\0';
+ /* Convert database name to a file name. */
+ len= build_table_filename(oldname, sizeof(oldname)-1,
+ oldname, "", "", 0);
+ /* Remove trailing slash. */
+ if (len && (oldname[len-1] == FN_LIBCHAR))
+ oldname[--len]= '\0';
+ /* Build new name as old + uuid. */
+ memcpy(newname, oldname, len);
+ newname[len++]= '-';
+ my_uuid(uuid);
+ my_uuid2str(uuid, newname + len);
+ newname[len + MY_UUID_STRING_LENGTH]= '\0';
+ DBUG_PRINT("si_objects", ("Rename '%s' to '%s'", oldname, newname));
+ rc= my_rename(oldname, newname, MYF(MY_WME));
+ if (rc)
+ {
+ /* Could not rename directory. Restore will fail. */
+ /* purecov: begin tested */
+ my_error(ER_DB_DROP_RMDIR, MYF(0), oldname, my_errno);
+ /* purecov: end */
+ }
+ else
+ {
+ /* Renamed directory. Add a warning. */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_RESTORE_RENAME, ER(ER_RESTORE_RENAME),
+ newname);
+ }
+ }
+ }
+ err:
+ DBUG_RETURN(rc);
+}
+
+///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
/**
Attachment: [text/bzr-bundle] bzr/ingo.struewing@sun.com-20090519092851-prf51bqsnznz2iu7.bundle