List:Commits« Previous MessageNext Message »
From:rsomla Date:December 11 2007 10:21am
Subject:bk commit into 6.0 tree (rafal:1.2748) BUG#33119
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of rafal. When rafal does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-12-11 11:21:35+01:00, rafal@quant.(none) +10 -0
  BUG#33119 (Online backup silently overwrites files).
  
  This patch makes backup to fail with error "Can't write to backup location '<path>'" if the
  file already exists. Backup tests are updated so that they don't try to overwrite existing
  files.
  
  Also, in case of failed BACKUP operation, the backup file is deleted if it was created at 
  its beginning.

  mysql-test/r/backup_errors.result@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +8 -0
    Results update.

  mysql-test/r/backup_no_data.result@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +12 -4
    Results update.

  mysql-test/t/backup_ddl_blocker.test@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +24 -2
    Since BACKUP don't overwrite existing files any more, remove each file before backing up to it.

  mysql-test/t/backup_errors.test@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +27 -5
    Added test for situation when existing file is about to be overwritten.

  mysql-test/t/backup_fkey.test@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +10 -2
    Since BACKUP don't overwrite existing files any more, remove each file before backing up to it.

  mysql-test/t/backup_no_data.test@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +19 -10
    Since BACKUP don't overwrite existing files any more, remove each file before backing up to it. 
    Don't mess with test database. 

  mysql-test/t/backup_progress.test@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +6 -1
    Since BACKUP don't overwrite existing files any more, remove each file before backing up to it.

  sql/backup/backup_kernel.h@stripped, 2007-12-11 11:21:29+01:00, rafal@quant.(none) +12 -0
    Added remove() method to Location class.

  sql/backup/kernel.cc@stripped, 2007-12-11 11:21:30+01:00, rafal@quant.(none) +32 -2
    - Added code to remove backup file in case of error.
    - Implementation of Location::remove() method for File_loc class.

  sql/backup/stream.cc@stripped, 2007-12-11 11:21:30+01:00, rafal@quant.(none) +1 -1
    Added O_EXCL flag when openning file for writting. This makes open fail if the file already exists. 

diff -Nrup a/mysql-test/r/backup_errors.result b/mysql-test/r/backup_errors.result
--- a/mysql-test/r/backup_errors.result	2007-11-06 19:32:22 +01:00
+++ b/mysql-test/r/backup_errors.result	2007-12-11 11:21:29 +01:00
@@ -8,8 +8,16 @@ RESTORE FROM 'test.bak';
 ERROR HY000: Can't read backup location 'test.bak'
 CREATE DATABASE adb;
 CREATE DATABASE bdb;
+CREATE TABLE bdb.t1(a int) ENGINE=MyISAM;
 BACKUP DATABASE adb TO '';
 ERROR HY000: Invalid backup location ''
+BACKUP DATABASE adb TO "bdb/t1.frm";
+ERROR HY000: Can't write to backup location 'bdb/t1.frm'
+BACKUP DATABASE adb TO "test.bak";
+backup_id
+#
+BACKUP DATABASE adb TO "test.bak";
+ERROR HY000: Can't write to backup location 'test.bak'
 DROP DATABASE IF EXISTS foo;
 Warnings:
 Note	1008	Can't drop database 'foo'; database doesn't exist
diff -Nrup a/mysql-test/r/backup_no_data.result b/mysql-test/r/backup_no_data.result
--- a/mysql-test/r/backup_no_data.result	2007-12-03 21:28:03 +01:00
+++ b/mysql-test/r/backup_no_data.result	2007-12-11 11:21:29 +01:00
@@ -1,5 +1,7 @@
 DROP DATABASE IF EXISTS empty_db;
+DROP DATABASE IF EXISTS other_db;
 CREATE DATABASE empty_db;
+CREATE DATABASE other_db;
 BACKUP DATABASE empty_db TO 'empty_db.bak';
 backup_id
 #
@@ -7,11 +9,12 @@ BACKUP DATABASE * TO 'all.bak';
 backup_id
 #
 DROP DATABASE empty_db;
-DROP DATABASE test;
+DROP DATABASE other_db;
 SHOW DATABASES;
 Database
 information_schema
 mysql
+test
 RESTORE FROM 'all.bak';
 backup_id
 #
@@ -20,9 +23,10 @@ Database
 information_schema
 empty_db
 mysql
+other_db
 test
 DROP DATABASE empty_db;
-DROP DATABASE test;
+DROP DATABASE other_db;
 RESTORE FROM 'empty_db.bak';
 backup_id
 #
@@ -31,6 +35,7 @@ Database
 information_schema
 empty_db
 mysql
+test
 SHOW TABLES IN empty_db;
 Tables_in_empty_db
 RESTORE FROM 'all.bak';
@@ -41,10 +46,11 @@ Database
 information_schema
 empty_db
 mysql
+other_db
 test
 SHOW TABLES IN empty_db;
 Tables_in_empty_db
-USE test;
+USE other_db;
 DROP TABLE IF EXISTS t1;
 Warnings:
 Note	1051	Unknown table 't1'
@@ -54,7 +60,7 @@ CREATE TABLE t1 (
 ) ENGINE=MEMORY DEFAULT CHARSET=latin1;
 USE empty_db;
 DROP VIEW IF EXISTS v1;
-CREATE VIEW v1 AS SELECT * FROM test.t1;
+CREATE VIEW v1 AS SELECT * FROM other_db.t1;
 BACKUP DATABASE empty_db TO 'empty_db.bak';
 backup_id
 #
@@ -63,6 +69,7 @@ Database
 information_schema
 empty_db
 mysql
+other_db
 test
 RESTORE FROM 'empty_db.bak';
 backup_id
@@ -71,3 +78,4 @@ USE empty_db;
 SHOW TABLES;
 Tables_in_empty_db
 DROP DATABASE IF EXISTS empty_db;
+DROP DATABASE IF EXISTS other_db;
diff -Nrup a/mysql-test/t/backup_ddl_blocker.test b/mysql-test/t/backup_ddl_blocker.test
--- a/mysql-test/t/backup_ddl_blocker.test	2007-12-06 19:05:56 +01:00
+++ b/mysql-test/t/backup_ddl_blocker.test	2007-12-11 11:21:29 +01:00
@@ -140,6 +140,8 @@ send ALTER TABLE bup_ddl_blocker.t2 ADD 
 connection con1;
 
 --echo con1: Backing up database -- will block with lock
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak
 send BACKUP DATABASE bup_ddl_blocker TO "bup_ddl_blocker.bak";
 
 connection con6;
@@ -285,6 +287,8 @@ DESCRIBE bup_ddl_blocker.t4;
 DROP TABLE bup_ddl_blocker.t1, bup_ddl_blocker.t3;
 
 # Get a backup to work with.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak
 --replace_column 1 #
 BACKUP DATABASE bup_ddl_blocker to 'bup_ddl_blocker_orig.bak';
 
@@ -456,6 +460,8 @@ send REPAIR TABLE bup_ddl_blocker.t2;
 connection con1;
 
 --echo con1: Backing up database -- will block with lock
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak
 send BACKUP DATABASE bup_ddl_blocker TO "bup_ddl_blocker.bak";
 
 connection con6;
@@ -595,6 +601,8 @@ SHOW TABLES;
 --source include/backup_ddl_create_data.inc
 
 # Get a backup to work with.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak
 --replace_column 1 #
 BACKUP DATABASE bup_ddl_blocker to 'bup_ddl_blocker_orig.bak';
 
@@ -764,6 +772,8 @@ send DROP TABLE bup_ddl_blocker.t2;
 connection con1;
 
 --echo con1: Backing up database -- will block with lock
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak
 send BACKUP DATABASE bup_ddl_blocker TO "bup_ddl_blocker.bak";
 
 connection con6;
@@ -900,6 +910,8 @@ SHOW TABLES;
 --source include/backup_ddl_create_data.inc
 
 # Get a backup to work with.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak
 --replace_column 1 #
 BACKUP DATABASE bup_ddl_blocker to 'bup_ddl_blocker_orig.bak';
 
@@ -1095,6 +1107,8 @@ send DROP DATABASE bup_ddl_blocker_2;
 connection con1;
 
 --echo con1: Backing up database -- will block with lock
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak
 send BACKUP DATABASE * TO "bup_ddl_blocker.bak";
 
 connection con6;
@@ -1260,6 +1274,8 @@ INSERT INTO bup_ddl_blocker_4.t1 VALUES 
 SHOW DATABASES LIKE 'bup_ddl_blocker_%';
 
 # Get a backup to work with.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak
 --replace_column 1 #
 BACKUP DATABASE bup_ddl_blocker_2, bup_ddl_blocker_4 to 'bup_ddl_blocker_orig.bak';
 
@@ -1455,6 +1471,8 @@ send ALTER DATABASE bup_ddl_blocker_2 CH
 connection con1;
 
 --echo con1: Backing up database -- will block with lock
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak
 send BACKUP DATABASE * TO "bup_ddl_blocker.bak";
 
 connection con6;
@@ -1642,6 +1660,8 @@ INSERT INTO bup_ddl_blocker_4.t1 VALUES 
 SHOW DATABASES LIKE 'bup_ddl_blocker_%';
 
 # Get a backup to work with.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak
 --replace_column 1 #
 BACKUP DATABASE bup_ddl_blocker_2, bup_ddl_blocker_4 to 'bup_ddl_blocker_orig.bak';
 
@@ -1951,8 +1971,10 @@ DROP TABLE test.t2;
 --echo con1: Cleanup
 DROP DATABASE bup_ddl_blocker;
 
-remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak;
-remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak;
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker_orig.bak;
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_ddl_blocker.bak;
 
 
 
diff -Nrup a/mysql-test/t/backup_errors.test b/mysql-test/t/backup_errors.test
--- a/mysql-test/t/backup_errors.test	2007-11-30 05:22:00 +01:00
+++ b/mysql-test/t/backup_errors.test	2007-12-11 11:21:29 +01:00
@@ -1,20 +1,42 @@
 --source include/not_embedded.inc
 
+# Check that BACKUP/RESTORE commands correctly report errors 
+#
+# TODO: When we know how to do that, check that the backup progress table
+# contains appropriate rows when errors have been detected.
+
 DROP DATABASE IF EXISTS adb;
 DROP DATABASE IF EXISTS bdb;
 
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/test.bak
+
 # non-existent backup archive
--- exec rm -f $MYSQLTEST_VARDIR/master-data/test.bak
 -- error ER_BACKUP_READ_LOC
 RESTORE FROM 'test.bak';
 
 CREATE DATABASE adb;
 CREATE DATABASE bdb;
+CREATE TABLE bdb.t1(a int) ENGINE=MyISAM;
 
-# bad archive name
--- error ER_BACKUP_INVALID_LOC
+# invalid location
+--error ER_BACKUP_INVALID_LOC
 BACKUP DATABASE adb TO '';
 
+# don't overwrite existing files
+--error ER_BACKUP_WRITE_LOC
+BACKUP DATABASE adb TO "bdb/t1.frm";
+
+--replace_column 1 #
+BACKUP DATABASE adb TO "test.bak";
+
+# don't overwrite existing backup image
+--error ER_BACKUP_WRITE_LOC
+BACKUP DATABASE adb TO "test.bak";
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/test.bak
+
 # non-existent database
 DROP DATABASE IF EXISTS foo;
 DROP DATABASE IF EXISTS bar;
@@ -27,5 +49,5 @@ BACKUP DATABASE test,foo,bdb,bar TO 'tes
 
 DROP DATABASE IF EXISTS adb;
 DROP DATABASE IF EXISTS bdb;
-
-
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/test.bak
diff -Nrup a/mysql-test/t/backup_fkey.test b/mysql-test/t/backup_fkey.test
--- a/mysql-test/t/backup_fkey.test	2007-11-30 05:22:00 +01:00
+++ b/mysql-test/t/backup_fkey.test	2007-12-11 11:21:29 +01:00
@@ -50,6 +50,8 @@ INSERT INTO backup_fkey.child VALUES (4,
 
 # Backup the database with fkey constraints preserved.
 --echo Backup the database originally.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey_orig.bak
 --replace_column 1 #
 BACKUP DATABASE backup_fkey TO 'backup_fkey_orig.bak';
 
@@ -65,6 +67,8 @@ DROP TABLE backup_fkey.parent;
 
 # Backup only the child table.
 --echo Backup the database without the parent table.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey.bak
 --replace_column 1 #
 BACKUP DATABASE backup_fkey TO 'backup_fkey.bak';
 
@@ -105,6 +109,8 @@ INSERT INTO backup_fkey.t1 VALUES ("06 T
 INSERT INTO backup_fkey.t1 VALUES ("07 Test #2 - foreign key constraints"); 
 
 --echo Backup the data
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey.bak
 --replace_column 1 #
 BACKUP DATABASE backup_fkey TO 'backup_fkey.bak';
 
@@ -141,6 +147,8 @@ SHOW VARIABLES LIKE 'foreign_key_checks%
 
 DROP DATABASE backup_fkey;
 
-remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey.bak;
-remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey_orig.bak;
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey.bak;
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_fkey_orig.bak;
 
diff -Nrup a/mysql-test/t/backup_no_data.test b/mysql-test/t/backup_no_data.test
--- a/mysql-test/t/backup_no_data.test	2007-12-03 21:28:08 +01:00
+++ b/mysql-test/t/backup_no_data.test	2007-12-11 11:21:29 +01:00
@@ -4,22 +4,27 @@ connect (backup,localhost,root,,);
 
 connection backup;
 
-# save empty test database on the side
---exec cp -rf $MYSQLTEST_VARDIR/master-data/test $MYSQLTEST_VARDIR/test.orig
 
 --disable_warnings
 DROP DATABASE IF EXISTS empty_db;
+DROP DATABASE IF EXISTS other_db;
 --enable_warnings
 
 CREATE DATABASE empty_db;
+CREATE DATABASE other_db;
 
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/empty_db.bak
 --replace_column 1 #
 BACKUP DATABASE empty_db TO 'empty_db.bak';
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/all.bak
 --replace_column 1 #
 BACKUP DATABASE * TO 'all.bak';
 
 DROP DATABASE empty_db;
-DROP DATABASE test;
+DROP DATABASE other_db;
 
 SHOW DATABASES;
 
@@ -29,7 +34,7 @@ RESTORE FROM 'all.bak';
 SHOW DATABASES;
 
 DROP DATABASE empty_db;
-DROP DATABASE test;
+DROP DATABASE other_db;
 
 --replace_column 1 #
 RESTORE FROM 'empty_db.bak';
@@ -45,7 +50,7 @@ SHOW TABLES IN empty_db;
 
 connection backup;
 
-USE test;
+USE other_db;
 
 DROP TABLE IF EXISTS t1;
 
@@ -60,8 +65,10 @@ USE empty_db;
 DROP VIEW IF EXISTS v1;
 --enable_warnings
 
-CREATE VIEW v1 AS SELECT * FROM test.t1;
+CREATE VIEW v1 AS SELECT * FROM other_db.t1;
 
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/empty_db.bak
 --replace_column 1 #
 BACKUP DATABASE empty_db TO 'empty_db.bak';
 
@@ -74,9 +81,11 @@ USE empty_db;
 
 SHOW TABLES;
 DROP DATABASE IF EXISTS empty_db;
+DROP DATABASE IF EXISTS other_db;
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/all.bak
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/empty_db.bak
 
-# restore test database to the exact state from the beginning of this test
---exec rm -rf $MYSQLTEST_VARDIR/master-data/test/*
---exec cp -rf $MYSQLTEST_VARDIR/test.orig $MYSQLTEST_VARDIR/master-data/test
---exec rm -rf $MYSQLTEST_VARDIR/test.orig/*
 
diff -Nrup a/mysql-test/t/backup_progress.test b/mysql-test/t/backup_progress.test
--- a/mysql-test/t/backup_progress.test	2007-12-06 22:42:58 +01:00
+++ b/mysql-test/t/backup_progress.test	2007-12-11 11:21:29 +01:00
@@ -62,6 +62,8 @@ SELECT get_lock("bp_starting_state", 0);
 connection con2;
 
 --echo con2: Send backup command.
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_progress_orig.bak
 send BACKUP DATABASE backup_progress to 'backup_progress_orig.bak';
 
 connection con1;
@@ -229,10 +231,13 @@ SELECT obp.* FROM mysql.online_backup_pr
 connection con1;
 
 --replace_column 1 #
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_progress_orig.bak
 --error 1049
 BACKUP DATABASE DOES_NOT_EXIST to 'backup_progress_orig.bak';
 
 DROP DATABASE backup_progress;
 
-remove_file $MYSQLTEST_VARDIR/master-data/backup_progress_orig.bak;
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/backup_progress_orig.bak;
 
diff -Nrup a/sql/backup/backup_kernel.h b/sql/backup/backup_kernel.h
--- a/sql/backup/backup_kernel.h	2007-11-30 21:14:08 +01:00
+++ b/sql/backup/backup_kernel.h	2007-12-11 11:21:29 +01:00
@@ -70,6 +70,18 @@ struct Location
   { return "Invalid location"; }
 
   /**
+    Remove any system resources connected to that location.
+
+    When location is opened for writing, some system resources will be usually
+    created (depending on the type of the location). For example, a file in the
+    file system. This method should remove/free any such resources. If no
+    resources were created, the method should do nothing.
+    
+    @returns OK on success, ERROR otherwise.
+   */ 
+  virtual result_t remove() =0;
+
+  /**
     Interpret string passed to BACKUP/RESTORE statement as backup location
     and construct corresponding Location object.
 
diff -Nrup a/sql/backup/kernel.cc b/sql/backup/kernel.cc
--- a/sql/backup/kernel.cc	2007-12-03 21:28:16 +01:00
+++ b/sql/backup/kernel.cc	2007-12-11 11:21:30 +01:00
@@ -246,10 +246,10 @@ execute_backup_command(THD *thd, LEX *le
 
   case SQLCOM_BACKUP:
   {
+    /* if set to true, backup location will be removed (e.g., upon failure) */
+    bool remove_location= FALSE; 
     backup::OStream *stream= open_for_write(*loc);
 
-    // TODO: report error if location exists
-
     if (!stream)
     {
       my_error(ER_BACKUP_WRITE_LOC,MYF(0),loc->describe());
@@ -352,6 +352,15 @@ execute_backup_command(THD *thd, LEX *le
     if (stop)
       report_ob_time(backup_prog_id, 0, stop);
 
+    /*
+      If the output stream was opened, a file or other system resource
+      (depending on the type of the backup location) could be created. Since
+      we failed to write backup image, this resource should be removed.
+      We set remove_location flag so that loc->remove() will be called after
+      closing the output stream.
+     */
+    remove_location= TRUE;
+
     BACKUP_BREAKPOINT("bp_error_state");
 
    finish_backup:
@@ -363,8 +372,14 @@ execute_backup_command(THD *thd, LEX *le
     BACKUP_BREAKPOINT("DDL_unblocked");
 
     if (stream)
+    {
       stream->close();
 
+      if (remove_location)
+        if (loc->remove() != OK)
+          res= res ? res : ERROR;
+    }
+
     break;
   }
 
@@ -1611,6 +1626,21 @@ struct File_loc: public Location
   const char* describe()
   { return path.c_ptr(); }
 
+  result_t remove()
+  {
+    int res= my_delete(path.c_ptr(),MYF(0));
+
+    /*
+      Ignore ENOENT error since it is ok if the file doesn't exist.
+     */
+    if (my_errno == ENOENT)
+      res= 0;
+
+    if (res)
+      sql_print_error(ER(ER_CANT_DELETE_FILE),path.c_ptr(),my_errno);
+
+    return res ? ERROR : OK;
+  }
 };
 
 
diff -Nrup a/sql/backup/stream.cc b/sql/backup/stream.cc
--- a/sql/backup/stream.cc	2007-11-30 09:23:30 +01:00
+++ b/sql/backup/stream.cc	2007-12-11 11:21:30 +01:00
@@ -147,7 +147,7 @@ bool Stream::rewind()
 
 
 OStream::OStream(const ::String &name):
-  Stream(name,O_WRONLY|O_CREAT|O_TRUNC), bytes(0)
+  Stream(name,O_WRONLY|O_CREAT|O_EXCL|O_TRUNC), bytes(0)
 {
   stream.write= stream_write;
   m_block_size=0; // use default block size provided by the backup stram library
Thread
bk commit into 6.0 tree (rafal:1.2748) BUG#33119rsomla11 Dec
  • RE: bk commit into 6.0 tree (rafal:1.2748) BUG#33119Chuck Bell11 Dec
    • Re: bk commit into 6.0 tree (rafal:1.2748) BUG#33119Rafal Somla12 Dec