List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:November 28 2008 10:14am
Subject:bzr commit into mysql-6.0 branch (jorgen.loland:2729)
View as plain text  
#At file:///localhome/jl208045/mysql/mergecaptain/mysql-6.0-backup-merge/

 2729 Jorgen Loland	2008-11-28 [merge]
      Merge mysql-6.0-backup -> mysql-6.0-backup-merge
modified:
  mysql-test/suite/backup/r/backup.result
  mysql-test/suite/backup/r/backup_errors.result
  mysql-test/suite/backup/r/backup_views.result
  mysql-test/suite/backup/t/backup.test
  mysql-test/suite/backup/t/backup_errors.test
  mysql-test/suite/backup/t/backup_myisam1.test
  mysql-test/suite/backup/t/backup_views.test
  sql/backup/backup_info.cc
  sql/backup/backup_info.h
  sql/backup/backup_kernel.h
  sql/backup/data_backup.cc
  sql/backup/image_info.cc
  sql/backup/image_info.h
  sql/backup/kernel.cc
  sql/backup/logger.cc
  sql/backup/logger.h
  sql/backup/restore_info.h
  sql/share/errmsg.txt
  sql/si_logs.h

=== modified file 'mysql-test/suite/backup/r/backup.result'
--- a/mysql-test/suite/backup/r/backup.result	2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/r/backup.result	2008-11-26 10:05:19 +0000
@@ -148,6 +148,35 @@ DROP DATABASE db1;
 DROP DATABASE db2;
 DROP DATABASE db3;
 SET DEBUG_SYNC= 'RESET';
+CREATE DATABASE db1;
+BACKUP DATABASE db1 TO 'db1.bkp';
+backup_id
+#
+SELECT MAX(backup_id) FROM mysql.backup_history INTO @bid;
+SELECT validity_point_time FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_time;
+SELECT binlog_file FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_file;
+SELECT binlog_pos FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_pos;
+DROP DATABASE db1;
+RESTORE FROM 'db1.bkp';
+backup_id
+#
+SELECT MAX(backup_id) FROM mysql.backup_history INTO @bid;
+SELECT validity_point_time = @vp_time FROM mysql.backup_history
+WHERE backup_id = @bid;
+validity_point_time = @vp_time
+1
+SELECT binlog_file = @vp_file FROM mysql.backup_history
+WHERE backup_id = @bid;
+binlog_file = @vp_file
+1
+SELECT binlog_pos = @vp_pos FROM mysql.backup_history
+WHERE backup_id = @bid;
+binlog_pos = @vp_pos
+1
+DROP DATABASE db1;
 DROP DATABASE IF EXISTS bup_default;
 CREATE DATABASE bup_default;
 CREATE TABLE bup_default.wide (

=== modified file 'mysql-test/suite/backup/r/backup_errors.result'
--- a/mysql-test/suite/backup/r/backup_errors.result	2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/r/backup_errors.result	2008-11-25 17:44:19 +0000
@@ -7,19 +7,36 @@ CREATE DATABASE bdb;
 CREATE TABLE bdb.t1(a int) ENGINE=MEMORY;
 BACKUP DATABASE adb TO '';
 ERROR HY000: Malformed file path ''
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Malformed file path ''
 BACKUP DATABASE adb TO "bdb/t1.frm";
 ERROR HY000: Can't write to backup location 'bdb/t1.frm' (file already exists?)
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Can't write to backup location 'bdb/t1.frm' (file already exists?)
 BACKUP DATABASE adb TO "test.bak";
 backup_id
 #
+SHOW WARNINGS;
+Level	Code	Message
 BACKUP DATABASE adb TO "test.bak";
 ERROR HY000: Can't write to backup location 'test.bak' (file already exists?)
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Can't write to backup location 'test.bak' (file already exists?)
 DROP DATABASE IF EXISTS foo;
 DROP DATABASE IF EXISTS bar;
 BACKUP DATABASE foo TO 'test.bak';
 ERROR 42000: Unknown database 'foo'
+SHOW WARNINGS;
+Level	Code	Message
+Error	1049	Unknown database 'foo'
 BACKUP DATABASE test,foo,bdb,bar TO 'test.bak';
 ERROR 42000: Unknown database 'foo,bar'
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Unknown database 'foo,bar'
 BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
 ERROR 42000: Not unique database: 'foo'
 use adb;
@@ -49,21 +66,39 @@ DROP DATABASE bdb;
 Backup of mysql, information_schema scenario 1
 BACKUP DATABASE mysql TO 't.bak';
 ERROR HY000: Database 'mysql' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'mysql' cannot be included in a backup
 Backup of mysql, information_schema scenario 2
 BACKUP DATABASE information_schema TO 't.bak';
 ERROR HY000: Database 'information_schema' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'information_schema' cannot be included in a backup
 Backup of mysql, information_schema scenario 3
 BACKUP DATABASE mysql, information_schema TO 't.bak';
 ERROR HY000: Database 'mysql' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'mysql' cannot be included in a backup
 Backup of mysql, information_schema scenario 4
 BACKUP DATABASE mysql, test TO 't.bak';
 ERROR HY000: Database 'mysql' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'mysql' cannot be included in a backup
 Backup of mysql, information_schema scenario 5
 BACKUP DATABASE information_schema, test TO 't.bak';
 ERROR HY000: Database 'information_schema' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'information_schema' cannot be included in a backup
 Backup of mysql, information_schema scenario 6
 BACKUP DATABASE mysql, information_schema, test TO 't.bak';
 ERROR HY000: Database 'mysql' cannot be included in a backup
+SHOW WARNINGS;
+Level	Code	Message
+Error	#	Database 'mysql' cannot be included in a backup
 Making copies of progress tables.
 CREATE TABLE IF NOT EXISTS test.ob_copy LIKE mysql.backup_history;
 CREATE TABLE IF NOT EXISTS test.obp_copy LIKE mysql.backup_progress;
@@ -78,7 +113,7 @@ DROP TABLE mysql.backup_history;
 Backup the database;
 BACKUP DATABASE test_ob_error TO 'ob_err.bak';
 ERROR HY000: Can't open the backup logs as tables. Check 'mysql.backup_history' and
'mysql.backup_progress' or run mysql_upgrade to repair.
-SHOW ERRORS;
+SHOW WARNINGS;
 Level	Code	Message
 Error	#	Table 'mysql.backup_history' doesn't exist
 Error	#	Cannot create backup/restore execution context
@@ -89,7 +124,7 @@ DROP TABLE mysql.backup_progress;
 Backup the database;
 BACKUP DATABASE test_ob_error TO 'ob_err.bak';
 ERROR HY000: Can't open the backup logs as tables. Check 'mysql.backup_history' and
'mysql.backup_progress' or run mysql_upgrade to repair.
-SHOW ERRORS;
+SHOW WARNINGS;
 Level	Code	Message
 Error	#	Table 'mysql.backup_progress' doesn't exist
 Error	#	Cannot create backup/restore execution context

=== modified file 'mysql-test/suite/backup/r/backup_views.result'
--- a/mysql-test/suite/backup/r/backup_views.result	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/r/backup_views.result	2008-11-25 17:44:19 +0000
@@ -277,10 +277,10 @@ DROP DATABASE bup_db2;
 Restore database.
 restore database with view dependency to other, non-existing db
 RESTORE FROM 'bup_objectview1.bak';
-ERROR HY000: Could not restore view `bup_db1`.`v5`. Please check the view definition for
possible missing dependencies.
+ERROR 42S02: Table 'bup_db2.t2' doesn't exist
 DROP DATABASE bup_db1;
 RESTORE FROM 'bup_objectview2.bak';
-ERROR HY000: Could not restore view `bup_db2`.`student_details`. Please check the view
definition for possible missing dependencies.
+ERROR 42S02: Table 'bup_db1.t3' doesn't exist
 DROP DATABASE bup_db2;
 RESTORE FROM 'bup_objectview.bak';
 backup_id

=== modified file 'mysql-test/suite/backup/t/backup.test'
--- a/mysql-test/suite/backup/t/backup.test	2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/t/backup.test	2008-11-26 10:05:19 +0000
@@ -180,11 +180,10 @@ SHOW CREATE TABLE tasking;
 
 # check that VP info was correctly read and reported
 
-SELECT validity_point_time = @vp_time FROM mysql.backup_history
-WHERE backup_id = @bid; 
-SELECT binlog_file = @vp_file FROM mysql.backup_history
-WHERE backup_id = @bid; 
-SELECT binlog_pos = @vp_pos FROM mysql.backup_history
+SELECT validity_point_time = @vp_time 
+   AND binlog_file = @vp_file
+   AND binlog_pos = @vp_pos
+FROM mysql.backup_history
 WHERE backup_id = @bid; 
 
 DROP DATABASE db1;
@@ -193,6 +192,51 @@ DROP DATABASE db3;
 SET DEBUG_SYNC= 'RESET';
 
 #
+# Check that PTR data (such as VP time and binlog positon) is correctly stored and read
+# when there are no tables to backup (BUG#40262). 
+#
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/db1.bkp
+CREATE DATABASE db1;
+
+--replace_column 1 #
+BACKUP DATABASE db1 TO 'db1.bkp';
+# get backup_id of the BACKUP operation. 
+SELECT MAX(backup_id) FROM mysql.backup_history INTO @bid;
+
+# store VP time and binlog position
+
+SELECT validity_point_time FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_time;
+SELECT binlog_file FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_file;
+SELECT binlog_pos FROM mysql.backup_history
+WHERE backup_id = @bid INTO @vp_pos;
+
+DROP DATABASE db1;
+
+# wait few seconds so that restore time != backup time
+--sleep 2
+
+--replace_column 1 #
+RESTORE FROM 'db1.bkp';
+# determine id of RESTORE operation
+SELECT MAX(backup_id) FROM mysql.backup_history INTO @bid;
+
+# check that VP info was correctly read and reported
+
+SELECT validity_point_time = @vp_time 
+   AND binlog_file = @vp_file
+   AND binlog_pos = @vp_pos
+FROM mysql.backup_history
+WHERE backup_id = @bid; 
+
+DROP DATABASE db1;
+--remove_file $MYSQLTEST_VARDIR/master-data/db1.bkp
+
+
+#
 # This test is for the default and snapshot online backup drivers
 #
 

=== modified file 'mysql-test/suite/backup/t/backup_errors.test'
--- a/mysql-test/suite/backup/t/backup_errors.test	2008-11-17 09:57:51 +0000
+++ b/mysql-test/suite/backup/t/backup_errors.test	2008-11-25 17:44:19 +0000
@@ -25,17 +25,25 @@ CREATE TABLE bdb.t1(a int) ENGINE=MEMORY
 # invalid location
 --error ER_BAD_PATH
 BACKUP DATABASE adb TO '';
+--replace_column 2 #
+SHOW WARNINGS;
 
 # don't overwrite existing files
 --error ER_BACKUP_WRITE_LOC
 BACKUP DATABASE adb TO "bdb/t1.frm";
+--replace_column 2 #
+SHOW WARNINGS;
 
 --replace_column 1 #
 BACKUP DATABASE adb TO "test.bak";
+--replace_column 2 #
+SHOW WARNINGS;
 
 # don't overwrite existing backup image
 --error ER_BACKUP_WRITE_LOC
 BACKUP DATABASE adb TO "test.bak";
+--replace_column 2 #
+SHOW WARNINGS;
 
 --remove_file $MYSQLTEST_VARDIR/master-data/test.bak
 
@@ -47,8 +55,11 @@ DROP DATABASE IF EXISTS bar;
 
 -- error ER_BAD_DB_ERROR
 BACKUP DATABASE foo TO 'test.bak';
+SHOW WARNINGS;
 -- error ER_BAD_DB_ERROR
 BACKUP DATABASE test,foo,bdb,bar TO 'test.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 # repeated database
 -- error ER_NONUNIQ_DB
@@ -117,6 +128,8 @@ DROP DATABASE bdb;
 --echo Backup of mysql, information_schema scenario 1
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE mysql TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -125,6 +138,8 @@ BACKUP DATABASE mysql TO 't.bak';
 --echo Backup of mysql, information_schema scenario 2
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE information_schema TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -133,6 +148,8 @@ BACKUP DATABASE information_schema TO 't
 --echo Backup of mysql, information_schema scenario 3
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE mysql, information_schema TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -141,6 +158,8 @@ BACKUP DATABASE mysql, information_schem
 --echo Backup of mysql, information_schema scenario 4
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE mysql, test TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -149,6 +168,8 @@ BACKUP DATABASE mysql, test TO 't.bak';
 --echo Backup of mysql, information_schema scenario 5
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE information_schema, test TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -157,6 +178,8 @@ BACKUP DATABASE information_schema, test
 --echo Backup of mysql, information_schema scenario 6
 --error ER_BACKUP_CANNOT_INCLUDE_DB
 BACKUP DATABASE mysql, information_schema, test TO 't.bak';
+--replace_column 2 #
+SHOW WARNINGS;
 
 --error 0, 1
 --remove_file $MYSQLTEST_VARDIR/master-data/t.bak
@@ -190,7 +213,7 @@ BACKUP DATABASE test_ob_error TO 'ob_err
 --error 0,1
 --remove_file $MYSQLTEST_VARDIR/master-data/ob_err.bak
 --replace_column 2 #
-SHOW ERRORS;
+SHOW WARNINGS;
 
 # Restore the table
 --echo Restoring the table
@@ -207,7 +230,7 @@ BACKUP DATABASE test_ob_error TO 'ob_err
 --error 0,1
 --remove_file $MYSQLTEST_VARDIR/master-data/ob_err.bak
 --replace_column 2 #
-SHOW ERRORS;
+SHOW WARNINGS;
 
 # Restore the table
 --echo Restoring the table

=== modified file 'mysql-test/suite/backup/t/backup_myisam1.test'
--- a/mysql-test/suite/backup/t/backup_myisam1.test	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/t/backup_myisam1.test	2008-11-25 17:44:19 +0000
@@ -24,5 +24,7 @@ BACKUP DATABASE mysqltest TO 'test.ba';
 # Cleanup from this test case
 #
 DROP DATABASE mysqltest;
+# Note: The backup file should not exist as BACKUP command failed.
+--error 1
 --remove_file $MYSQLTEST_VARDIR/master-data/test.ba
 

=== modified file 'mysql-test/suite/backup/t/backup_views.test'
--- a/mysql-test/suite/backup/t/backup_views.test	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/t/backup_views.test	2008-11-25 17:44:19 +0000
@@ -205,14 +205,14 @@ DROP DATABASE bup_db2;
 
 --echo restore database with view dependency to other, non-existing db
 
---error ER_BACKUP_CANT_RESTORE_VIEW
+--error ER_NO_SUCH_TABLE
 RESTORE FROM 'bup_objectview1.bak';
 
 # An incomplete bup_db1 was created by the failing restore operation.
 # Remove it before trying restore of bup_db2.
 DROP DATABASE bup_db1;
 
---error ER_BACKUP_CANT_RESTORE_VIEW
+--error ER_NO_SUCH_TABLE
 RESTORE FROM 'bup_objectview2.bak';
 
 # An incomplete bup_db2 was created by the failing restore operation.

=== modified file 'sql/backup/backup_info.cc'
--- a/sql/backup/backup_info.cc	2008-11-05 09:41:15 +0000
+++ b/sql/backup/backup_info.cc	2008-11-25 17:44:19 +0000
@@ -87,11 +87,11 @@ Backup_info::find_backup_engine(const ba
 
   // See if table has native backup engine
 
-  storage_engine_ref se= get_storage_engine(m_ctx.m_thd, tbl);
+  storage_engine_ref se= get_storage_engine(m_thd, tbl);
   
   if (!se)
   {
-    m_ctx.fatal_error(ER_NO_STORAGE_ENGINE, tbl.describe(buf));
+    m_log.report_error(ER_NO_STORAGE_ENGINE, tbl.describe(buf));
     DBUG_RETURN(NULL);
   }
   
@@ -126,7 +126,7 @@ Backup_info::find_backup_engine(const ba
   if (!snap)
     if (has_native_backup(se))
     {
-      Native_snapshot *nsnap= new Native_snapshot(m_ctx, se);
+      Native_snapshot *nsnap= new Native_snapshot(m_log, se);
 
       /*
         Check if the snapshot object is valid - in particular has successfully
@@ -175,7 +175,7 @@ Backup_info::find_backup_engine(const ba
   }
 
   if (!snap)
-    m_ctx.fatal_error(ER_BACKUP_NO_BACKUP_DRIVER,tbl.describe(buf));
+    m_log.report_error(ER_BACKUP_NO_BACKUP_DRIVER,tbl.describe(buf));
   
   DBUG_RETURN(snap);
 }
@@ -295,13 +295,16 @@ Backup_info::Dep_node::get_key(const uch
 
 /**
   Create @c Backup_info instance and prepare it for populating with objects.
- 
+  
+  @param[in] log     A logger used to report errors
+  @param[in] thd     THD handle
+
   Snapshots created by the built-in backup engines are added to @c snapshots
   list to be used in the backup engine selection algorithm in 
   @c find_backup_engine().
  */
-Backup_info::Backup_info(Backup_restore_ctx &ctx)
-  :m_ctx(ctx), m_state(Backup_info::ERROR), native_snapshots(8),
+Backup_info::Backup_info(backup::Logger &log, THD *thd)
+  :m_log(log), m_thd(thd), m_state(Backup_info::ERROR), native_snapshots(8),
    m_dep_list(NULL), m_dep_end(NULL), 
    m_srout_end(NULL), m_view_end(NULL), m_trigger_end(NULL), m_event_end(NULL)
 {
@@ -318,7 +321,7 @@ Backup_info::Backup_info(Backup_restore_
                 Dep_node::get_key, Dep_node::free, MYF(0)))
   {
     // Allocation failed. Error has been reported, but not logged to backup logs
-    m_ctx.log_error(ER_OUT_OF_RESOURCES);
+    m_log.log_error(ER_OUT_OF_RESOURCES);
     return;
   }
 
@@ -328,10 +331,10 @@ Backup_info::Backup_info(Backup_restore_
     element on that list, as a "catch all" entry. 
    */
 
-  snap= new Nodata_snapshot(m_ctx);             // logs errors
+  snap= new Nodata_snapshot(m_log);             // logs errors
   if (!snap)
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return;
   }
 
@@ -341,14 +344,14 @@ Backup_info::Backup_info(Backup_restore_
   if (snapshots.push_back(snap))
   {
     // Allocation failed. Error has been reported, but not logged to backup logs
-    m_ctx.log_error(ER_OUT_OF_RESOURCES);
+    m_log.log_error(ER_OUT_OF_RESOURCES);
     return;
   }
 
-  snap= new CS_snapshot(m_ctx);                 // logs errors
+  snap= new CS_snapshot(m_log);                 // logs errors
   if (!snap)
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return;
   }
 
@@ -358,14 +361,14 @@ Backup_info::Backup_info(Backup_restore_
   if (snapshots.push_back(snap))
   {
     // Allocation failed. Error has been reported, but not logged to backup logs
-    m_ctx.log_error(ER_OUT_OF_RESOURCES);
+    m_log.log_error(ER_OUT_OF_RESOURCES);
     return;                                   // Error has been logged
   }
 
-  snap= new Default_snapshot(m_ctx);            // logs errors
+  snap= new Default_snapshot(m_log);            // logs errors
   if (!snap)
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return;
   }
 
@@ -375,7 +378,7 @@ Backup_info::Backup_info(Backup_restore_
   if (snapshots.push_back(snap))
   {
     // Allocation failed. Error has been reported, but not logged to backup logs
-    m_ctx.log_error(ER_OUT_OF_RESOURCES);
+    m_log.log_error(ER_OUT_OF_RESOURCES);
     return;                                   // Error has been logged
   }
 
@@ -417,7 +420,7 @@ int Backup_info::close()
   // report backup drivers used in the image
   
   for (ushort n=0; n < snap_count(); ++n)
-    m_ctx.report_driver(m_snap[n]->name());
+    m_log.report_driver(m_snap[n]->name());
   
   m_state= CLOSED;
   return 0;
@@ -465,7 +468,7 @@ backup::Image_info::Ts* Backup_info::add
 
   if (!ts)
   {
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_TS, name);
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_TS, name);
     return NULL;
   }
 
@@ -479,7 +482,7 @@ backup::Image_info::Ts* Backup_info::add
 
   if (!n1)
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return NULL;
   }
 
@@ -513,7 +516,7 @@ backup::Image_info::Db* Backup_info::add
   
   if (!db)
   {
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_DB, name->ptr());
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_DB, name->ptr());
     return NULL;
   }
 
@@ -550,7 +553,7 @@ int Backup_info::add_dbs(List< ::LEX_STR
     
     if (is_internal_db_name(&db_name))
     {
-      m_ctx.fatal_error(ER_BACKUP_CANNOT_INCLUDE_DB, db_name.c_ptr());
+      m_log.report_error(ER_BACKUP_CANNOT_INCLUDE_DB, db_name.c_ptr());
       goto error;
     }
     
@@ -589,7 +592,7 @@ int Backup_info::add_dbs(List< ::LEX_STR
 
   if (!unknown_dbs.is_empty())
   {
-    m_ctx.fatal_error(ER_BAD_DB_ERROR, unknown_dbs.c_ptr());
+    m_log.report_error(ER_BAD_DB_ERROR, unknown_dbs.c_ptr());
     goto error;
   }
 
@@ -614,11 +617,11 @@ int Backup_info::add_all_dbs()
   using namespace obs;
 
   int res= 0;
-  Obj_iterator *dbit= get_databases(m_ctx.m_thd);
+  Obj_iterator *dbit= get_databases(m_thd);
   
   if (!dbit)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DBS);
+    m_log.report_error(ER_BACKUP_LIST_DBS);
     return ERROR;
   }
   
@@ -701,11 +704,11 @@ int Backup_info::add_db_items(Db &db)
 
   // Add tables.
 
-  Obj_iterator *it= get_db_tables(m_ctx.m_thd, &db.name());
+  Obj_iterator *it= get_db_tables(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_TABLES, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_TABLES, db.name().ptr());
     return ERROR;
   }
   
@@ -731,7 +734,7 @@ int Backup_info::add_db_items(Db &db)
 
     // If this table uses a tablespace, add this tablespace to the catalogue.
 
-    obj= get_tablespace_for_table(m_ctx.m_thd, &db.name(), &tbl->name());
+    obj= get_tablespace_for_table(m_thd, &db.name(), &tbl->name());
 
     if (obj)
     {
@@ -748,11 +751,11 @@ int Backup_info::add_db_items(Db &db)
   // Add other objects.
 
   delete it;  
-  it= get_db_stored_procedures(m_ctx.m_thd, &db.name());
+  it= get_db_stored_procedures(m_thd, &db.name());
   
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_SROUT, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_SROUT, db.name().ptr());
     goto error;
   }
   
@@ -760,11 +763,11 @@ int Backup_info::add_db_items(Db &db)
     goto error;
 
   delete it;
-  it= get_db_stored_functions(m_ctx.m_thd, &db.name());
+  it= get_db_stored_functions(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_SROUT, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_SROUT, db.name().ptr());
     goto error;
   }
   
@@ -772,11 +775,11 @@ int Backup_info::add_db_items(Db &db)
     goto error;
 
   delete it;
-  it= get_db_views(m_ctx.m_thd, &db.name());
+  it= get_db_views(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_VIEWS, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_VIEWS, db.name().ptr());
     goto error;
   }
   
@@ -784,11 +787,11 @@ int Backup_info::add_db_items(Db &db)
     goto error;
 
   delete it;
-  it= get_db_events(m_ctx.m_thd, &db.name());
+  it= get_db_events(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_EVENTS, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_EVENTS, db.name().ptr());
     goto error;
   }
   
@@ -796,11 +799,11 @@ int Backup_info::add_db_items(Db &db)
     goto error;
   
   delete it;
-  it= get_db_triggers(m_ctx.m_thd, &db.name());
+  it= get_db_triggers(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_TRIGGERS, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_TRIGGERS, db.name().ptr());
     goto error;
   }
   
@@ -808,11 +811,11 @@ int Backup_info::add_db_items(Db &db)
     goto error;
   
   delete it;
-  it= get_all_db_grants(m_ctx.m_thd, &db.name());
+  it= get_all_db_grants(m_thd, &db.name());
 
   if (!it)
   {
-    m_ctx.fatal_error(ER_BACKUP_LIST_DB_PRIV, db.name().ptr());
+    m_log.report_error(ER_BACKUP_LIST_DB_PRIV, db.name().ptr());
     goto error;
   }
 
@@ -889,8 +892,8 @@ backup::Image_info::Table* Backup_info::
   
   if (!tbl)
   {
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_TABLE, 
-                      dbi.name().ptr(), t.name().ptr());
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_TABLE, 
+                       dbi.name().ptr(), t.name().ptr());
     return NULL;
   }
 
@@ -943,7 +946,7 @@ int Backup_info::add_view_deps(obs::Obj 
   
   // Get an iterator to iterate over base views of the given one.
 
-  obs::Obj_iterator *it= obs::get_view_base_views(m_ctx.m_thd, db_name, name);
+  obs::Obj_iterator *it= obs::get_view_base_views(m_thd, db_name, name);
 
   if (!it)
     return ERROR;
@@ -1086,7 +1089,7 @@ Backup_info::add_db_object(Db &db, const
   
   if (res == get_dep_node_res::ERROR)
   {
-    m_ctx.fatal_error(error, db.name().ptr(), name->ptr());
+    m_log.report_error(error, db.name().ptr(), name->ptr());
     return NULL;
   }
 
@@ -1101,7 +1104,7 @@ Backup_info::add_db_object(Db &db, const
     if (type == BSTREAM_IT_VIEW)
       if (add_view_deps(*obj))
       {
-        m_ctx.fatal_error(error, db.name().ptr(), name->ptr());
+        m_log.report_error(error, db.name().ptr(), name->ptr());
         return NULL;
       } 
 
@@ -1122,7 +1125,7 @@ Backup_info::add_db_object(Db &db, const
  
   if (!o)
   {
-    m_ctx.fatal_error(error, db.name().ptr(), name->ptr());
+    m_log.report_error(error, db.name().ptr(), name->ptr());
     return NULL;
   }
 
@@ -1342,7 +1345,7 @@ int Backup_info::Global_iterator::init()
   if (!m_it)
   {
     const Backup_info* info= static_cast<const Backup_info*>(&m_info);
-    return info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    return info->m_log.report_error(ER_OUT_OF_RESOURCES);
   }
   next();                                       // Never errors
 
@@ -1388,7 +1391,7 @@ Backup_info::Global_iterator::next()
     if (!m_it)
     {
       const Backup_info* info= static_cast<const Backup_info*>(&m_info);
-      info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+      info->m_log.report_error(ER_OUT_OF_RESOURCES);
       mode= DONE;
       return FALSE;
     }
@@ -1471,7 +1474,7 @@ backup::Image_info::Iterator* Backup_inf
   Global_iterator* it = new Global_iterator(*this);
   if (it == NULL) 
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return NULL;
   }    
   if (it->init())                               // Error has been logged
@@ -1488,7 +1491,7 @@ backup::Image_info::Iterator* Backup_inf
   Perdb_iterator* it = new Perdb_iterator(*this);
   if (it == NULL) 
   {
-    m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    m_log.report_error(ER_OUT_OF_RESOURCES);
     return NULL;
   }    
   if (it->init())                               // Error has been logged

=== modified file 'sql/backup/backup_info.h'
--- a/sql/backup/backup_info.h	2008-11-13 13:02:36 +0000
+++ b/sql/backup/backup_info.h	2008-11-25 17:44:19 +0000
@@ -31,9 +31,8 @@ class Backup_info: public backup::Image_
 {
  public:
 
-  Backup_restore_ctx &m_ctx;
+  backup::Logger &m_log;
 
-  Backup_info(Backup_restore_ctx&);
   ~Backup_info();
 
   bool is_valid();
@@ -48,10 +47,18 @@ class Backup_info: public backup::Image_
 
  private:
 
+  /*
+    Note: constructor is private because instances of this class are supposed
+    to be created only with Backup_restore_ctx::prepare_for_backup() method.
+  */
+  Backup_info(backup::Logger&, THD*);
+
   // Prevent copying/assignments
   Backup_info(const Backup_info&);
   Backup_info& operator=(const Backup_info&);
 
+  THD *m_thd;
+
   class Global_iterator; ///< Iterates over global items (for which meta-data is
stored).
   class Perdb_iterator;  ///< Iterates over all per-database objects (except tables).
 
@@ -169,6 +176,7 @@ class Backup_info: public backup::Image_
   friend int ::bcat_get_item_create_query(st_bstream_image_header *catalogue,
                                struct st_bstream_item_info *item,
                                bstream_blob *stmt);
+  friend class Backup_restore_ctx;  // Needs access to the constructor.
 };
 
 /// Check if instance is correctly created.

=== modified file 'sql/backup/backup_kernel.h'
--- a/sql/backup/backup_kernel.h	2008-11-17 09:57:51 +0000
+++ b/sql/backup/backup_kernel.h	2008-11-25 17:44:19 +0000
@@ -75,8 +75,6 @@ class Backup_restore_ctx: public backup:
 
   int do_backup();
   int do_restore(bool overwrite);
-  int fatal_error(int, ...);
-  int log_error(int, ...);
 
   int close();
 
@@ -102,7 +100,8 @@ class Backup_restore_ctx: public backup:
   /** 
     @brief State of a context object. 
     
-    Backup/restore can be performed only if object is prepared for that operation.
+    Backup/restore can be performed only if object is prepared for that 
+    operation.
    */
   enum { CREATED,
          PREPARED_FOR_BACKUP,
@@ -111,10 +110,22 @@ class Backup_restore_ctx: public backup:
 
   ulonglong m_thd_options;  ///< For saving thd->options.
   /**
-    If backup/restore was interrupted by an error, this member stores the error 
-    number.
-   */ 
+    @brief Tells if context object is in error state.
+
+    In case of fatal error, the context object is put into an error state 
+    by setting @m_error to non-zero value. This can be the code of
+    the detected error but currently the exact value is not used.
+
+    When in error state, public methods of Backup_restore_ctx do not try
+    to perform their operations but report an error instead. @c Is_valid() 
+    will return FALSE for an object in error state.
+
+    @note The error state is an internal state of the context object. The
+    object can enter this state only as a result of executing one of its 
+    methods.
+  */
   int m_error;
+  int fatal_error(int);
   
   ::String  m_path;   ///< Path to where the backup image file is located.
 
@@ -149,8 +160,6 @@ class Backup_restore_ctx: public backup:
   
   int report_stream_open_failure(int open_error, const LEX_STRING *location);
 
-  friend class Backup_info;
-  friend class Restore_info;
   friend int backup_init();
   friend void backup_shutdown();
   friend bstream_byte* bstream_alloc(unsigned long int);
@@ -179,32 +188,31 @@ void Backup_restore_ctx::disable_fkey_co
 }
 
 /**
-  Report error and move context object into error state.
+  Move context object into error state.
   
   After this method is called the context object is in error state and
-  cannot be normally used. It still can be examined for saved error messages.
-  The code of the error reported here is saved in m_error member.
+  cannot be normally used. The provided error code is saved in m_error 
+  member.
   
   Only one fatal error can be reported. If context is already in error
   state when this method is called, it does nothing.
+
+  @note Context object should enter error state only as a result of executing
+  one of its methods. Thus this private helper method is intended to be used 
+  only from within Backup_restore_ctx class.  
   
   @return error code given as input or stored in the context object if
-  a fatal error was reported before.
+  it is already in error state.
  */ 
 inline
-int Backup_restore_ctx::fatal_error(int error_code, ...)
+int Backup_restore_ctx::fatal_error(int error_code)
 {
+  m_remove_loc= TRUE;
+
   if (m_error)
     return m_error;
 
-  va_list args;
-
   m_error= error_code;
-  m_remove_loc= TRUE;
-
-  va_start(args,error_code);
-  v_report_error(backup::log_level::ERROR, error_code, args);
-  va_end(args);
 
   return error_code;
 }

=== modified file 'sql/backup/data_backup.cc'
--- a/sql/backup/data_backup.cc	2008-10-30 20:02:15 +0000
+++ b/sql/backup/data_backup.cc	2008-11-26 10:05:19 +0000
@@ -248,7 +248,7 @@ class Scheduler
  private:
 
   LIST   *m_pumps, *m_last;
-  Logger *m_log;        ///< used to report errors if not NULL
+  Logger &m_log;        ///< for reporting errors          
   uint   m_count;       ///< current number of pumps
   size_t m_total;       ///< accumulated position of all drivers
   size_t m_init_left;   ///< how much of init data is left (estimate)
@@ -256,7 +256,7 @@ class Scheduler
   Output_stream &m_str; ///< stream to which we write
   bool   cancelled;     ///< true if backup process was cancelled
 
-  Scheduler(Output_stream &s, Logger *log)
+  Scheduler(Output_stream &s, Logger &log)
     :init_count(0), prepare_count(0), finish_count(0),
     m_pumps(NULL), m_last(NULL), m_log(log),
     m_count(0), m_total(0), m_init_left(0), m_known_count(0),
@@ -412,6 +412,70 @@ int unblock_commits(THD *thd)
 }
 
 /**
+  Store information about validity point in @c Backup_info structure.
+  
+  @note This function is called in a time critical synchronization phase
+  of the backup process. Therefore it should not perform any time consuming
+  or potentially waiting operations such as I/O.
+
+  @returns 0 on success.
+*/
+static
+int save_vp_info(Backup_info &info)
+{
+  LOG_INFO binlog_pos;
+  int ret=0;
+
+  /*
+    Save VP creation time.
+  */
+  info.save_vp_time(my_time(0));
+
+  /*
+    Save current binlog position if it is enabled.
+  */
+  if (mysql_bin_log.is_open())
+    if (mysql_bin_log.get_current_log(&binlog_pos))
+    {
+      info.m_log.report_error(ER_BACKUP_BINLOG);
+      ret= TRUE;
+    }
+    else
+      info.save_binlog_pos(binlog_pos);
+
+  /*
+    Save master's binlog information if we are a connected slave.
+  */
+  if (obs::is_slave() && active_mi)
+    info.save_master_pos(*active_mi);
+
+  return ret;
+}
+
+/**
+  Log validity point information.
+
+  Information such as validity point time is logged using backup logger which,
+  in particular, writes it to backup history and progress logs.
+  
+  @note Logging the information may involve time consuming I/O. Therefore this
+  function should not be called in the time critical synchronization phase, but
+  after the synchronisation has been done.
+*/ 
+static
+void report_vp_info(Backup_info &info)
+{
+  info.m_log.report_vp_time(info.get_vp_time(), 
+                            TRUE // = also write to progress log
+                           );
+  if (info.flags & BSTREAM_FLAG_BINLOG)
+    info.m_log.report_binlog_pos(info.binlog_pos);
+  if (info.master_pos.pos)
+    info.m_log.report_master_binlog_pos(info.master_pos);
+}
+
+
+/**
   Save data from tables being backed up.
 
   Function initializes and controls backup drivers which create the image
@@ -424,17 +488,30 @@ int write_table_data(THD* thd, Backup_in
 {
   DBUG_ENTER("backup::write_table_data");
 
+  /*
+    If there are no tables to backup, there is nothing to do in this function
+    except for storing and reporting the validity point info.
+    
+    Note that since DDLs are disabled and backup image contains no table data, 
+    any time during backup operation is a good validity time -- there is no 
+    issue of synchronising the data stored in the image with the data in the 
+    rest of the server.
+  */ 
   if (info.snap_count() == 0 || info.table_count() == 0) // nothing to backup
-    DBUG_RETURN(0);
+  {
+    int res= save_vp_info(info);    // logs errors
+    if (!res)
+      report_vp_info(info);
+    DBUG_RETURN(res);
+  }
 
-  Scheduler   sch(s, &info.m_ctx);          // scheduler instance
+  Logger      &log= info.m_log;
+  Scheduler   sch(s, log);          // scheduler instance
   List<Scheduler::Pump>  inactive;  // list of images not yet being created
 
   // keeps maximal init size for images in inactive list
   size_t      max_init_size=0;
 
-  time_t      vp_time;              // to store validity point time
-
   DBUG_PRINT("backup_data",("initializing scheduler"));
 
   // add unknown "at end" drivers to scheduler, rest to inactive list
@@ -448,9 +525,15 @@ int write_table_data(THD* thd, Backup_in
 
     Scheduler::Pump *p= new Scheduler::Pump(*i, s);
 
-    if (!p || !p->is_valid())
+    if (!p)
     {
-      info.m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+      log.report_error(ER_OUT_OF_RESOURCES);
+      goto error;
+    }
+    if (!p->is_valid())
+    {
+      log.report_error(ER_BACKUP_CREATE_BACKUP_DRIVER,p->m_name);
+      delete p;
       goto error;
     }
 
@@ -458,7 +541,7 @@ int write_table_data(THD* thd, Backup_in
 
     if (init_size == Driver::UNKNOWN_SIZE)
     {
-      if (sch.add(p))
+      if (sch.add(p))    // logs errors
         goto error;
     }
     else
@@ -471,7 +554,7 @@ int write_table_data(THD* thd, Backup_in
         /* Allocation failed. 
            Error has been reported, but not logged to backup logs.
         */
-        info.m_ctx.log_error(ER_OUT_OF_RESOURCES);
+        log.log_error(ER_OUT_OF_RESOURCES);
         goto error;
       }
     }
@@ -529,7 +612,7 @@ int write_table_data(THD* thd, Backup_in
 
     // poll drivers
 
-    if (sch.step())
+    if (sch.step())    // logs errors
       goto error;
   }
 
@@ -571,7 +654,7 @@ int write_table_data(THD* thd, Backup_in
     if (error)
       goto error;
 
-    if (sch.prepare())
+    if (sch.prepare())    // logs errors
       goto error;
 
     while (sch.prepare_count > 0)
@@ -582,9 +665,7 @@ int write_table_data(THD* thd, Backup_in
     
     DBUG_PRINT("backup_data",("-- SYNC PHASE --"));
 
-    LOG_INFO binlog_pos;
-    
-    info.m_ctx.report_state(BUP_VALIDITY_POINT);
+    log.report_state(BUP_VALIDITY_POINT);
     /*
       This breakpoint is used to assist in testing state changes for
       the backup progress. It is not to be used to indicate actual
@@ -597,39 +678,13 @@ int write_table_data(THD* thd, Backup_in
     */
 
     DEBUG_SYNC(thd, "before_backup_data_lock");
-    if (sch.lock())
+    if (sch.lock())    // logs errors
       goto error;
 
-    /*
-      Save binlog information for point in time recovery on restore.
-    */
-    if (mysql_bin_log.is_open())
-      if (mysql_bin_log.get_current_log(&binlog_pos))
-      {
-        info.m_ctx.fatal_error(ER_BACKUP_BINLOG);
-        goto error;
-      }
-
-    /*
-      If we are a connected slave, write master's binlog information to
-      the progress log for later use.
-    */
-    st_bstream_binlog_pos master_pos;
-    master_pos.pos= 0;
-    master_pos.file= 0;
-    if (obs::is_slave() && active_mi)
-    {
-      master_pos.pos= (ulong)active_mi->master_log_pos;
-      master_pos.file= active_mi->master_log_name;
-    }
-
-    /*
-      Save VP creation time.
-    */
-    vp_time= my_time(0);
+    save_vp_info(info);
 
     DEBUG_SYNC(thd, "before_backup_data_unlock");
-    if (sch.unlock())
+    if (sch.unlock())    // logs errors
       goto error;
 
     /*
@@ -640,25 +695,9 @@ int write_table_data(THD* thd, Backup_in
     if (error)
       goto error;
 
-    // Report and save information about VP
-
-    info.save_vp_time(vp_time);
-    info.m_ctx.report_vp_time(vp_time, TRUE); // TRUE = also write to progress log
-
-    if (mysql_bin_log.is_open())
-    {
-      info.save_binlog_pos(binlog_pos);
-      info.m_ctx.report_binlog_pos(info.binlog_pos);
-    }
+    report_vp_info(info);
 
-    /*
-      If we are a slave and the master's binlog position has been recorded
-      write it to the log.
-    */
-    if (obs::is_slave() && master_pos.pos)
-      info.m_ctx.report_master_binlog_pos(master_pos);
-
-    info.m_ctx.report_state(BUP_RUNNING);
+    log.report_state(BUP_RUNNING);
     DEBUG_SYNC(thd, "after_backup_binlog");
 
     /**** VP creation (end) ********************************************/
@@ -819,9 +858,6 @@ int Scheduler::step()
 
     case backup_state::ERROR:
       remove_pump(p);   // Note: never errors.
-      if (res)
-        cancel_backup(); // we hit an error - bail out
-                         // Note: cancel_backup() never errors.
       break;
 
     default: break;
@@ -846,11 +882,14 @@ int Scheduler::add(Pump *p)
   if (!p)  // no pump to add
     return 0;
 
-  p->set_logger(m_log);
+  p->set_logger(&m_log);
   p->start_pos= avg;
 
-  if (p->begin())
-    goto error;
+  if (p->begin())  // logs errors
+  {
+    delete p;
+    return ERROR;
+  }
 
   // in case of error, above call should return non-zero code (and report error)
   DBUG_ASSERT(p->state != backup_state::ERROR);
@@ -894,12 +933,6 @@ int Scheduler::add(Pump *p)
                             (unsigned long)m_init_left));
 
   return 0;
-
- error:
-
-  delete p;
-  cancel_backup();
-  return ERROR;
 }
 
 /// Move backup pump to the end of scheduler's list.
@@ -971,9 +1004,9 @@ int Scheduler::prepare()
 
   for (Pump_iterator it(*this); it; ++it)
   {
-    if (it->prepare())
+    if (it->prepare())  // logs errors
     {
-      cancel_backup();  // Note: never errors.
+      remove_pump(it);  // Note: never errors.
       return ERROR;
     }
     if (it->state == backup_state::PREPARING)
@@ -994,9 +1027,9 @@ int Scheduler::lock()
   DBUG_PRINT("backup_data",("calling lock() for all drivers"));
 
   for (Pump_iterator it(*this); it; ++it)
-   if (it->lock())
+   if (it->lock())    // logs errors
    {
-     cancel_backup();  // Note: never errors.
+     remove_pump(it);  // Note: never errors.
      return ERROR;
    }
 
@@ -1013,9 +1046,9 @@ int Scheduler::unlock()
 
   for(Pump_iterator it(*this); it; ++it)
   {
-    if (it->unlock())
+    if (it->unlock())   // logs errors
     {
-      cancel_backup();  // Note: never errors.
+      remove_pump(it);  // Note: never errors.
       return ERROR;
     }
     if (it->state == backup_state::FINISHING)
@@ -1072,9 +1105,7 @@ int Backup_pump::begin()
   if (ERROR == m_drv->begin(m_bw.buf_size))
   {
     state= backup_state::ERROR;
-    // We check if logger is always setup. Later the assertion can
-    // be replaced with "if (m_log)"
-    DBUG_ASSERT(m_log);
+    if (m_log)
       m_log->report_error(ER_BACKUP_INIT_BACKUP_DRIVER, m_name);
     return ERROR;
   }
@@ -1092,7 +1123,7 @@ int Backup_pump::end()
     if (ERROR == m_drv->end())
     {
       state= backup_state::ERROR;
-      DBUG_ASSERT(m_log);
+      if (m_log)
         m_log->report_error(ER_BACKUP_STOP_BACKUP_DRIVER, m_name);
       return ERROR;
     }
@@ -1121,9 +1152,9 @@ int Backup_pump::prepare()
   case ERROR:
   default:
     state= backup_state::ERROR;
-    DBUG_ASSERT(m_log);
+    if (m_log)
       m_log->report_error(ER_BACKUP_PREPARE_DRIVER, m_name);
-      return ERROR;
+    return ERROR;
   }
 
   DBUG_PRINT("backup_data",(" preparing %s, goes to %s state",
@@ -1138,7 +1169,7 @@ int Backup_pump::lock()
   if (ERROR == m_drv->lock())
   {
     state= backup_state::ERROR;
-    DBUG_ASSERT(m_log);
+    if (m_log)
       m_log->report_error(ER_BACKUP_CREATE_VP, m_name);
     return ERROR;
   }
@@ -1154,7 +1185,7 @@ int Backup_pump::unlock()
   if (ERROR == m_drv->unlock())
   {
     state= backup_state::ERROR;
-    DBUG_ASSERT(m_log);
+    if (m_log)
       m_log->report_error(ER_BACKUP_UNLOCK_DRIVER, m_name);
     return ERROR;
   }
@@ -1167,7 +1198,7 @@ int Backup_pump::cancel()
   if (ERROR == m_drv->cancel())
   {
     state= backup_state::ERROR;
-    DBUG_ASSERT(m_log);
+    if (m_log)
       m_log->report_error(ER_BACKUP_CANCEL_BACKUP, m_name);
     return ERROR;
   }
@@ -1248,7 +1279,7 @@ int Backup_pump::pump(size_t *howmuch)
 
         case Block_writer::ERROR:
         default:
-          DBUG_ASSERT(m_log);
+          if (m_log)
             m_log->report_error(ER_BACKUP_GET_BUF);
           state= backup_state::ERROR;
           return ERROR;
@@ -1293,7 +1324,7 @@ int Backup_pump::pump(size_t *howmuch)
 
       case ERROR:
       default:
-        DBUG_ASSERT(m_log);
+        if (m_log)
           m_log->report_error(ER_BACKUP_GET_DATA, m_name);
         state= backup_state::ERROR;
         return ERROR;
@@ -1328,7 +1359,7 @@ int Backup_pump::pump(size_t *howmuch)
 
       case Block_writer::ERROR:
 
-        DBUG_ASSERT(m_log);
+        if (m_log)
           m_log->report_error(ER_BACKUP_WRITE_DATA, m_name, m_buf.table_num);
         state= backup_state::ERROR;
         return ERROR;
@@ -1364,18 +1395,50 @@ namespace backup {
  */
 int restore_table_data(THD *thd, Restore_info &info, Input_stream &s)
 {
+  st_bstream_data_chunk chunk_info; // For reading chunks from the stream.
+
   DBUG_ENTER("restore::restore_table_data");
 
   enum { READING, SENDING, DONE, ERROR } state= READING;
 
+  /*
+    If there are no tables stored in the image, there is nothing to do in this
+    function. However, we must call bstream_rd_data_chunk() which will absorb
+    the 0x00 byte signalling end of (the empty) table data chunk sequence.
+  */ 
   if (info.snap_count() == 0 || info.table_count() == 0) // nothing to restore
+  {
+    int res= bstream_rd_data_chunk(&s, &chunk_info);
+    if (res != BSTREAM_EOC)
+    {
+       info.m_log.report_error(res == BSTREAM_ERROR ?
+                                        ER_BACKUP_READ_DATA :
+                                        ER_BACKUP_UNEXPECTED_DATA);
+       DBUG_RETURN(ERROR);
+    }
     DBUG_RETURN(0);
+  }
 
-  Restore_driver* drv[256];
+  Logger &log= info.m_log;
 
-  if (info.snap_count() > 256)
+  /* Drv[n] points at restore driver used to process snapshot n. */
+  Restore_driver* drv[MAX_SNAP_COUNT];
+  /*
+    Active[n] is not NULL if driver drv[n] has been activated. Such driver needs 
+    an end() or cancel() call to shut it down properly.
+  */ 
+  Restore_driver* active[MAX_SNAP_COUNT];
+  /*
+    Bad_drivers string for holding comma separated list of drivers which
+    signalled errors during shutdown. If non-empty, an error will be logged
+    at the end of the function (finish: label).
+   */   
+  String bad_drivers;
+
+  if (info.snap_count() > MAX_SNAP_COUNT)
   {
-    info.m_ctx.fatal_error(ER_BACKUP_TOO_MANY_IMAGES, info.snap_count(), 256);
+    log.report_error(ER_BACKUP_TOO_MANY_IMAGES,
+                     info.snap_count(), MAX_SNAP_COUNT);
     DBUG_RETURN(ERROR);
   }
 
@@ -1384,7 +1447,7 @@ int restore_table_data(THD *thd, Restore
 
   for (uint n=0; n < info.snap_count(); ++n)
   {
-    drv[n]= NULL;
+    active[n]= drv[n]= NULL;
 
     Snapshot_info *snap= info.m_snap[n];
 
@@ -1395,7 +1458,7 @@ int restore_table_data(THD *thd, Restore
     res= snap->get_restore_driver(drv[n]);
     if (res == backup::ERROR)
     {
-      info.m_ctx.fatal_error(ER_BACKUP_CREATE_RESTORE_DRIVER, snap->name());
+      log.report_error(ER_BACKUP_CREATE_RESTORE_DRIVER, snap->name());
       goto error;
     };   
  }
@@ -1406,9 +1469,11 @@ int restore_table_data(THD *thd, Restore
     res= drv[n]->begin(0);
     if (res == backup::ERROR)
     {
-      info.m_ctx.fatal_error(ER_BACKUP_INIT_RESTORE_DRIVER, info.m_snap[n]->name());
+      log.report_error(ER_BACKUP_INIT_RESTORE_DRIVER, info.m_snap[n]->name());
       goto error;
     }
+    
+    active[n]= drv[n];
   }
 
   DEBUG_SYNC(thd, "restore_in_progress");
@@ -1426,8 +1491,6 @@ int restore_table_data(THD *thd, Restore
 
     // main data reading loop
 
-    st_bstream_data_chunk chunk_info;
-
     while ( state != DONE && state != ERROR )
     {
       switch (state) {
@@ -1449,9 +1512,8 @@ int restore_table_data(THD *thd, Restore
           break;
 
         case BSTREAM_ERROR:
-          info.m_ctx.fatal_error(ER_BACKUP_READ_DATA);
+          log.report_error(ER_BACKUP_READ_DATA);
         default:
-          state= ERROR;
           goto error;
 
         }
@@ -1491,7 +1553,8 @@ int restore_table_data(THD *thd, Restore
          */
         DBUG_ASSERT(snap && drvr);
 
-        switch( drvr->send_data(buf) ) {
+        ret= drvr->send_data(buf);
+        switch (ret) {
 
         case backup::OK:
           info.data_size += buf.size;
@@ -1504,8 +1567,13 @@ int restore_table_data(THD *thd, Restore
         case backup::ERROR:
           if( errors > MAX_ERRORS )
           {
-            info.m_ctx.fatal_error(ER_BACKUP_SEND_DATA, buf.table_num, snap->name());
-            state= ERROR;
+            log.report_error(ER_BACKUP_SEND_DATA, buf.table_num, snap->name());
+            /*
+              If driver signals error then it is not active any longer - neither 
+              ->end() nor ->cancel() should be called on it, only ->free(). 
+              This is why we need to remove it from active[] array.
+            */
+            active[snap_num]= NULL;
             goto error;
           }
           errors++;
@@ -1516,8 +1584,7 @@ int restore_table_data(THD *thd, Restore
         default:
           if( repeats > MAX_REPEATS )
           {
-            info.m_ctx.fatal_error(ER_BACKUP_SEND_DATA_RETRY, repeats, snap->name());
-            state= ERROR;
+            log.report_error(ER_BACKUP_SEND_DATA_RETRY, repeats, snap->name());
             goto error;
           }
           repeats++;
@@ -1526,7 +1593,7 @@ int restore_table_data(THD *thd, Restore
 
       default:
         break;
-      } // switch(state)
+      } // switch(ret)
 
     } // main reading loop
 
@@ -1536,49 +1603,69 @@ int restore_table_data(THD *thd, Restore
   }
 
   DEBUG_SYNC(::current_thd, "restore_table_data_before_end");
-  
-  { // Shutting down drivers
 
-    String bad_drivers;
+  // Call end() for all active drivers.
 
-    for (uint n=0; n < info.snap_count(); ++n)
-    {
-      if (!drv[n])
-        continue;
+  for (uint n=0; n < info.snap_count(); ++n)
+  {
+    if (!active[n])
+      continue;
 
-      DBUG_PRINT("restore",("Shutting down restore driver %s",
-                            info.m_snap[n]->name()));
-      res= drv[n]->end();
-      if (res == backup::ERROR)
-      {
-        state= ERROR;
+    DBUG_PRINT("restore",("Shutting down restore driver %s",
+                           info.m_snap[n]->name()));
+    res= active[n]->end();
+    if (res == backup::ERROR)
+    {
+      state= ERROR;
 
-        if (!bad_drivers.is_empty())
-          bad_drivers.append(",");
-        bad_drivers.append(info.m_snap[n]->name());
-      }
-      drv[n]->free();                           // Never errors
+      if (!bad_drivers.is_empty())
+        bad_drivers.append(",");
+      bad_drivers.append(info.m_snap[n]->name());
     }
-
-    if (!bad_drivers.is_empty())
-      info.m_ctx.report_error(ER_BACKUP_STOP_RESTORE_DRIVERS, bad_drivers.c_ptr());
   }
 
-  DBUG_RETURN(state == ERROR ? backup::ERROR : 0);
+  goto finish;
 
- error:
+error:
+
+  state= ERROR;
 
   DBUG_PRINT("restore",("Cancelling restore process"));
 
+  // Call cancel() for all active drivers
+
   for (uint n=0; n < info.snap_count(); ++n)
   {
-    if (!drv[n])
+    if (!active[n])
       continue;
 
+    DBUG_PRINT("restore",("Cancelling restore driver %s",
+                           info.m_snap[n]->name()));
+    res= active[n]->cancel();
+
+    if (res)
+    {
+      if (!bad_drivers.is_empty())
+        bad_drivers.append(",");
+      bad_drivers.append(info.m_snap[n]->name());
+    }
+  }
+
+finish:  
+
+  if (!bad_drivers.is_empty())
+    log.report_error(ER_BACKUP_STOP_RESTORE_DRIVERS, bad_drivers.c_ptr());
+
+  // Call free() for all existing drivers
+
+  for (uint n=0; n < info.snap_count(); ++n)
+  {
+    if (!drv[n])
+      continue;
     drv[n]->free();                             // Never errors
   }
 
-  DBUG_RETURN(backup::ERROR);
+  DBUG_RETURN(state == ERROR ? backup::ERROR : 0);
 }
 
 

=== modified file 'sql/backup/image_info.cc'
--- a/sql/backup/image_info.cc	2008-11-05 09:41:15 +0000
+++ b/sql/backup/image_info.cc	2008-11-26 10:05:19 +0000
@@ -1,4 +1,5 @@
 #include "../mysql_priv.h"
+#include "../rpl_mi.h"
 
 #include "image_info.h"
 #include "be_native.h"
@@ -50,6 +51,7 @@ Image_info::Image_info()
 #endif
 
   bzero(m_snap, sizeof(m_snap));
+  bzero(&master_pos, sizeof(master_pos));
 }
 
 Image_info::~Image_info()
@@ -169,8 +171,7 @@ int Image_info::add_snapshot(Snapshot_in
 {
   uint num= st_bstream_image_header::snap_count++;
 
-  // The limit of 256 snapshots is imposed by backup stream format.  
-  if (num > 256)
+  if (num > MAX_SNAP_COUNT)
     return -1;
   
   m_snap[num]= &snap;
@@ -384,6 +385,14 @@ Image_info::Obj *find_obj(const Image_in
   }
 }
 
+void Image_info::save_master_pos(const ::Master_info &mi)
+{
+  // store binlog coordinates
+  master_pos.pos=  static_cast<unsigned long int>(mi.master_log_pos);
+  master_pos.file= const_cast<char*>(mi.master_log_name);
+}
+
+
 } // backup namespace
 
 template class Map<uint, backup::Image_info::Db>;

=== modified file 'sql/backup/image_info.h'
--- a/sql/backup/image_info.h	2008-11-05 09:41:15 +0000
+++ b/sql/backup/image_info.h	2008-11-26 10:05:19 +0000
@@ -10,6 +10,16 @@
 #include <backup_stream.h> // for st_bstream_* types
 #include <backup/backup_aux.h>  // for Map template
 
+/**
+  @brief The maximal number of table data snapshots per backup image.
+  
+  @note This limit is determined by the backup image format used and can
+  not be changed. Currently we use version 1 of the image format in which
+  one byte is used to store snapshot numbers, hence the limit is 256.
+*/ 
+#define MAX_SNAP_COUNT  256
+
+
 class Backup_restore_ctx;
 
 namespace backup {
@@ -75,6 +85,7 @@ public: // public interface
    // info about image (most of it is in the st_bstream_image_header base
 
    size_t     data_size;      ///< How much of table data is saved in the image.
+   st_bstream_binlog_pos  master_pos; ///< To store master position info.
 
    ulong      table_count() const;
    uint       db_count() const;
@@ -101,12 +112,8 @@ public: // public interface
    /**
      Pointers to @c Snapshot_info objects corresponding to the snapshots
      present in the image.
-     
-     We can have at most 256 different snapshots which is a limitation imposed
-     by the backup stream library (the number of snapshots is stored inside 
-     backup image using one byte field).
     */ 
-   Snapshot_info *m_snap[256];
+   Snapshot_info *m_snap[MAX_SNAP_COUNT];
    
    // save timing & binlog info 
    
@@ -115,6 +122,7 @@ public: // public interface
    void save_vp_time(const time_t time);   
 
    void save_binlog_pos(const ::LOG_INFO&);
+   void save_master_pos(const ::Master_info&);
 
    time_t get_vp_time() const;
 

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-11-20 13:53:41 +0000
+++ b/sql/backup/kernel.cc	2008-11-25 17:44:19 +0000
@@ -156,11 +156,8 @@ execute_backup_command(THD *thd, LEX *le
     folders in the path could have been moved, deleted, etc.
   */
   if (backupdir->length() && my_access(backupdir->c_ptr(), (F_OK|W_OK)))
-  {
-    context.fatal_error(ER_BACKUP_BACKUPDIR, backupdir->c_ptr());
     DBUG_RETURN(send_error(context, ER_BACKUP_BACKUPDIR, backupdir->c_ptr()));
-  }
-
+ 
   switch (lex->sql_command) {
 
   case SQLCOM_BACKUP:
@@ -197,7 +194,7 @@ execute_backup_command(THD *thd, LEX *le
 
     if (info->db_count() == 0)
     {
-      context.fatal_error(ER_BACKUP_NOTHING_TO_BACKUP);
+      context.report_error(ER_BACKUP_NOTHING_TO_BACKUP);
       DBUG_RETURN(send_error(context, ER_BACKUP_NOTHING_TO_BACKUP));
     }
 
@@ -256,23 +253,21 @@ execute_backup_command(THD *thd, LEX *le
 }
 
 /**
-  Report errors.
+  Sends error notification after failed backup/restore operation.
 
-  Current implementation reports the last error saved in the logger if it exist.
-  Otherwise it reports error given by @c error_code.
+  @param[in]  ctx  The context of the backup/restore operation.
+  @param[in]  error_code  Error to be reported if no errors reported yet.
 
-  @returns 0 on success, error code otherwise.
- */
-int send_error(Backup_restore_ctx &log, int error_code, ...)
+  If an error has been already reported then nothing is done - the first 
+  logged error will be send to the client. Otherwise, if no errors were 
+  reported yet, the given error is sent to the client (but not reported).
+  
+  @returns The error code given as argument.
+*/
+static
+int send_error(Backup_restore_ctx &context, int error_code, ...)
 {
-  util::SAVED_MYSQL_ERROR *error= log.last_saved_error();
-
-  if (error && !util::report_mysql_error(log.thd(), error, error_code))
-  {
-    if (error->code)
-      error_code= error->code;
-  }
-  else // there are no error information in the logger - report error_code
+  if (!context.error_reported())
   {
     char buf[ERRMSGSIZE + 20];
     va_list args;
@@ -284,8 +279,8 @@ int send_error(Backup_restore_ctx &log, 
     va_end(args);
   }
 
-  if (log.backup::Logger::m_state == backup::Logger::RUNNING)
-    log.report_stop(my_time(0), FALSE); // FASLE = no success
+  if (context.backup::Logger::m_state == backup::Logger::RUNNING)
+    context.report_stop(my_time(0), FALSE); // FASLE = no success
   return error_code;
 }
 
@@ -296,6 +291,8 @@ int send_error(Backup_restore_ctx &log, 
   Currently the id of the operation is returned to the client. It can
   be used to select correct entries from the backup progress tables.
 
+  @note If an error has been reported, send_error() is invoked instead.
+
   @returns 0 on success, error code otherwise.
 */
 int send_reply(Backup_restore_ctx &context)
@@ -306,6 +303,9 @@ int send_reply(Backup_restore_ctx &conte
 
   DBUG_ENTER("send_reply");
 
+  if (context.error_reported())
+    return send_error(context, ER_UNKNOWN_ERROR);
+
   /*
     Send field list.
   */
@@ -336,9 +336,9 @@ int send_reply(Backup_restore_ctx &conte
   DBUG_RETURN(0);
 
  err:
-  DBUG_RETURN(context.fatal_error(ER_BACKUP_SEND_REPLY,
-                                  context.m_type == backup::Logger::BACKUP
-                                  ? "BACKUP" : "RESTORE"));
+  DBUG_RETURN(context.report_error(ER_BACKUP_SEND_REPLY,
+                                   context.m_type == backup::Logger::BACKUP
+                                   ? "BACKUP" : "RESTORE"));
 }
 
 
@@ -497,22 +497,17 @@ int Backup_restore_ctx::prepare(String *
   if (m_error)
     return m_error;
   
-  // Prepare error reporting context.
-  
-  mysql_reset_errors(m_thd, 0);                 // Never errors
-  m_thd->no_warnings_for_error= FALSE;
-
-  save_errors();                                // Never errors
-
+  int ret= 0;
 
   /*
     Check access for SUPER rights. If user does not have SUPER, fail with error.
+
+    In case of error, we write only to backup logs, because check_global_access()
+    pushes the same error on the error stack.
   */
-  if (check_global_access(m_thd, SUPER_ACL))
-  {
-    fatal_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, "SUPER");
-    return m_error;
-  }
+  ret= check_global_access(m_thd, SUPER_ACL);
+  if (ret)
+    return fatal_error(log_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, "SUPER"));
 
   /*
     Check if another BACKUP/RESTORE is running and if not, register 
@@ -529,7 +524,10 @@ int Backup_restore_ctx::prepare(String *
   pthread_mutex_unlock(&run_lock);
 
   if (m_error)
+  {
+    report_error(ER_BACKUP_RUNNING);
     return m_error;
+  }
 
   // check if location is valid (we assume it is a file path)
 
@@ -551,10 +549,7 @@ int Backup_restore_ctx::prepare(String *
 #endif
 
   if (bad_filename)
-  {
-    fatal_error(ER_BAD_PATH, location.str);
-    return m_error;
-  }
+    return fatal_error(report_error(ER_BAD_PATH, location.str));
 
   /*
     Computer full path to backup file.
@@ -569,18 +564,13 @@ int Backup_restore_ctx::prepare(String *
   mem_alloc= new Mem_allocator();
 
   if (!mem_alloc)
-  {
-    fatal_error(ER_OUT_OF_RESOURCES);
-    return m_error;
-  }
+    return fatal_error(report_error(ER_OUT_OF_RESOURCES));
 
   // Freeze all meta-data. 
 
-  if (obs::ddl_blocker_enable(m_thd))
-  {
-    fatal_error(ER_DDL_BLOCK);
-    return m_error;
-  }
+  ret= obs::ddl_blocker_enable(m_thd);
+  if (ret)
+    return fatal_error(report_error(ER_DDL_BLOCK));
 
   return 0;
 }
@@ -614,7 +604,7 @@ Backup_restore_ctx::prepare_for_backup(S
   if (m_error)
     return NULL;
   
-  if (Logger::init(BACKUP, query))
+  if (Logger::init(BACKUP, query))      // Logs errors
   {
     fatal_error(ER_BACKUP_LOGGER_INIT);
     return NULL;
@@ -640,10 +630,13 @@ Backup_restore_ctx::prepare_for_backup(S
   
   if (!s)
   {
-    fatal_error(ER_OUT_OF_RESOURCES);
+    fatal_error(report_error(ER_OUT_OF_RESOURCES));
     return NULL;
   }
-  
+
+  // Mark that the file should be removed unless operation completes successfuly
+  m_remove_loc= TRUE;
+
   int my_open_status= s->open();
   if (my_open_status != 0)
   {
@@ -655,16 +648,20 @@ Backup_restore_ctx::prepare_for_backup(S
     Create backup catalogue.
    */
 
-  Backup_info *info= new Backup_info(*this);    // Logs errors
+  Backup_info *info= new Backup_info(*this, m_thd);    // Logs errors
 
   if (!info)
   {
-    fatal_error(ER_OUT_OF_RESOURCES);
+    fatal_error(report_error(ER_OUT_OF_RESOURCES));
     return NULL;
   }
 
   if (!info->is_valid())
-    return NULL;    // Error has been logged by Backup_Info constructor
+  {
+    // Error has been logged by Backup_info constructor
+    fatal_error(ER_BACKUP_BACKUP_PREPARE);
+    return NULL;    
+  }
 
   /*
     If binlog is enabled, set BSTREAM_FLAG_BINLOG in the header to indicate
@@ -735,7 +732,7 @@ Backup_restore_ctx::prepare_for_restore(
   
   if (!s)
   {
-    fatal_error(ER_OUT_OF_RESOURCES);
+    fatal_error(report_error(ER_OUT_OF_RESOURCES));
     return NULL;
   }
   
@@ -750,45 +747,57 @@ Backup_restore_ctx::prepare_for_restore(
     Create restore catalogue.
    */
 
-  Restore_info *info= new Restore_info(*this);  // reports errors
+  Restore_info *info= new Restore_info(*this, m_thd);  // reports errors
 
   if (!info)
   {
-    fatal_error(ER_OUT_OF_RESOURCES);
+    fatal_error(report_error(ER_OUT_OF_RESOURCES));
     return NULL;
   }
 
   if (!info->is_valid())
+  {
+    // Errors are logged by Restore_info constructor. 
+    fatal_error(ER_BACKUP_RESTORE_PREPARE); 
     return NULL;
+  }
 
   info->save_start_time(when);
   m_catalog= info;
 
+  int ret;
+
   /*
-    Read catalogue from the input stream.
+    Read header and catalogue from the input stream.
    */
 
-  if (read_header(*info, *s))
+  ret= read_header(*info, *s);  // Can log errors via callback functions.
+  if (ret)
   {
-    fatal_error(ER_BACKUP_READ_HEADER);
+    if (!error_reported())
+      report_error(ER_BACKUP_READ_HEADER);
+    fatal_error(ret);
     return NULL;
   }
 
   if (s->next_chunk() != BSTREAM_OK)
   {
-    fatal_error(ER_BACKUP_NEXT_CHUNK);
+    fatal_error(report_error(ER_BACKUP_NEXT_CHUNK));
     return NULL;
   }
 
-  if (read_catalog(*info, *s))
+  ret= read_catalog(*info, *s);  // Can log errors via callback functions.
+  if (ret)
   {
-    fatal_error(ER_BACKUP_READ_HEADER);
+    if (!error_reported())
+      report_error(ER_BACKUP_READ_HEADER);
+    fatal_error(ret);
     return NULL;
   }
 
   if (s->next_chunk() != BSTREAM_OK)
   {
-    fatal_error(ER_BACKUP_NEXT_CHUNK);
+    fatal_error(report_error(ER_BACKUP_NEXT_CHUNK));
     return NULL;
   }
 
@@ -835,6 +844,7 @@ Backup_restore_ctx::prepare_for_restore(
 int Backup_restore_ctx::lock_tables_for_restore()
 {
   TABLE_LIST *tables= NULL;
+  int ret;
 
   /*
     Iterate over all tables in all snapshots and create a linked TABLE_LIST
@@ -855,7 +865,7 @@ int Backup_restore_ctx::lock_tables_for_
       if (!ptr)
       {
         // Error has been reported, but not logged to backup logs
-        return log_error(ER_OUT_OF_RESOURCES);
+        return fatal_error(log_error(ER_OUT_OF_RESOURCES));
       }
 
       tables= backup::link_table_list(*ptr, tables); // Never errors
@@ -872,16 +882,13 @@ int Backup_restore_ctx::lock_tables_for_
     Note 2: Skiping tmp tables is also important because otherwise a tmp table
     can occlude a regular table with the same name (BUG#33574).
   */ 
-  if (open_and_lock_tables_derived(m_thd, tables,
-                                   FALSE, /* do not process derived tables */
-                                   MYSQL_OPEN_SKIP_TEMPORARY 
+  ret= open_and_lock_tables_derived(m_thd, tables,
+                                    FALSE, /* do not process derived tables */
+                                    MYSQL_OPEN_SKIP_TEMPORARY 
                                           /* do not open tmp tables */
-                                  )
-     )
-  {
-    fatal_error(ER_BACKUP_OPEN_TABLES,"RESTORE");
-    return m_error;
-  }
+                                   );
+  if (ret)
+    return fatal_error(report_error(ER_BACKUP_OPEN_TABLES,"RESTORE"));
 
   m_tables_locked= TRUE;
   return 0;
@@ -906,39 +913,6 @@ void Backup_restore_ctx::unlock_tables()
 
 
 /**
-  Report error and move context object into error state without pushing the 
-  error on the server's warning stack.  
-  
-  Similar to @c fatal_error, but does not push the error on the
-  server's warning stack.  To be used when an error is reported from a
-  server function that has already pushed the error on the warning stack.
-  
-  @return error code given as input or stored in the context object if
-  a fatal error was reported before.
- */ 
-inline
-int Backup_restore_ctx::log_error(int error_code, ...)
-{
-  if (m_error)
-    return m_error;
-
-  bool saved = push_errors(FALSE);         // Do not use warning stack
-  
-  m_error= error_code;
-  m_remove_loc= TRUE;
-
-  va_list args;
-  va_start(args,error_code);
-  v_report_error(backup::log_level::ERROR, error_code, args);
-  va_end(args);
-
-  push_errors(saved);                      // Reset
-
-  return error_code;
-}
-
-
-/**
   Destroy a backup/restore context.
   
   This should reverse all settings made when context was created and prepared.
@@ -952,7 +926,6 @@ int Backup_restore_ctx::log_error(int er
  */ 
 int Backup_restore_ctx::close()
 {
-  int error= 0;
   if (m_state == CLOSED)
     return 0;
 
@@ -986,7 +959,7 @@ int Backup_restore_ctx::close()
   if (m_stream && !m_stream->close())
   {
     // Note error, but complete clean-up
-    error= ER_BACKUP_CLOSE;
+    fatal_error(report_error(ER_BACKUP_CLOSE));
   }
 
   if (m_catalog)
@@ -1000,31 +973,25 @@ int Backup_restore_ctx::close()
    */
   if (m_remove_loc && m_state == PREPARED_FOR_BACKUP)
   {
-    int res= my_delete(m_path.c_ptr(), MYF(0));
+    int ret= my_delete(m_path.c_ptr(), MYF(0));
 
     /*
       Ignore ENOENT error since it is ok if the file doesn't exist.
      */
-    if (res && my_errno != ENOENT)
-    {
-      error= ER_CANT_DELETE_FILE;
-    }
+    if (ret && my_errno != ENOENT)
+      fatal_error(report_error(ER_CANT_DELETE_FILE, m_path.c_ptr(), my_errno));
   }
 
   /* We report completion of the operation only if no errors were detected,
      and logger has been initialized.
   */
-  if (!error)
+  if (!m_error)
   {
     if (backup::Logger::m_state == backup::Logger::RUNNING)
     {
       report_stop(when, TRUE);
     }
   }
-  else
-  {
-    fatal_error(error);                         // Log error
-  }
 
   /* 
     Destroy backup stream's memory allocator (this frees memory)
@@ -1045,7 +1012,7 @@ int Backup_restore_ctx::close()
   pthread_mutex_unlock(&run_lock);
 
   m_state= CLOSED;
-  return error;
+  return m_error;
 }
 
 /**
@@ -1068,6 +1035,7 @@ int Backup_restore_ctx::do_backup()
   
   using namespace backup;
 
+  int ret;
   Output_stream &s= *static_cast<Output_stream*>(m_stream);
   Backup_info   &info= *static_cast<Backup_info*>(m_catalog);
 
@@ -1078,27 +1046,33 @@ int Backup_restore_ctx::do_backup()
   DBUG_PRINT("backup",("Writing preamble"));
   DEBUG_SYNC(m_thd, "backup_before_write_preamble");
 
-  if (write_preamble(info, s))
+  ret= write_preamble(info, s);  // Can Log errors via callback functions.
+  if (ret)
   {
-    fatal_error(ER_BACKUP_WRITE_HEADER);
-    DBUG_RETURN(m_error);
+    if (!error_reported())
+      report_error(ER_BACKUP_WRITE_HEADER);
+    DBUG_RETURN(fatal_error(ret));
   }
 
   DBUG_PRINT("backup",("Writing table data"));
 
   DEBUG_SYNC(m_thd, "before_backup_data");
 
-  if (write_table_data(m_thd, info, s)) // logs errors
-    DBUG_RETURN(send_error(*this, ER_BACKUP_BACKUP));
+  ret= write_table_data(m_thd, info, s); // logs errors
+  if (ret)
+    DBUG_RETURN(fatal_error(ret));
 
   DBUG_PRINT("backup",("Writing summary"));
 
-  if (write_summary(info, s))
-  {
-    fatal_error(ER_BACKUP_WRITE_SUMMARY);
-    DBUG_RETURN(m_error);
-  }
+  ret= write_summary(info, s);  
+  if (ret)
+    DBUG_RETURN(fatal_error(report_error(ER_BACKUP_WRITE_SUMMARY)));
 
+  /*
+    Now backup image has been written. Set m_remove_loc to FALSE, so that the
+    backup file is not removed in Backup_restore_ctx::close().
+  */
+  m_remove_loc= FALSE;
   report_stats_post(info);                      // Never errors
 
   DBUG_PRINT("backup",("Backup done."));
@@ -1135,9 +1109,7 @@ int Backup_restore_ctx::restore_triggers
 
   Image_info::Iterator *dbit= m_catalog->get_dbs();
   if (!dbit)
-  {
-    DBUG_RETURN(fatal_error(ER_OUT_OF_RESOURCES));
-  }
+    DBUG_RETURN(fatal_error(report_error(ER_OUT_OF_RESOURCES)));
 
   // create all trigers and collect events in the events list
   
@@ -1146,9 +1118,8 @@ int Backup_restore_ctx::restore_triggers
     Image_info::Iterator *it=
                    
m_catalog->get_db_objects(*static_cast<Image_info::Db*>(obj));
     if (!it)
-    {
-      DBUG_RETURN(fatal_error(ER_OUT_OF_RESOURCES));
-    }
+      DBUG_RETURN(fatal_error(report_error(ER_OUT_OF_RESOURCES)));
+
     while ((obj= (*it)++))
       switch (obj->type()) {
       
@@ -1157,7 +1128,7 @@ int Backup_restore_ctx::restore_triggers
         if (events.push_back(obj))
         {
           // Error has been reported, but not logged to backup logs
-          DBUG_RETURN(log_error(ER_OUT_OF_RESOURCES)); 
+          DBUG_RETURN(fatal_error(log_error(ER_OUT_OF_RESOURCES))); 
         }
         break;
       
@@ -1167,8 +1138,9 @@ int Backup_restore_ctx::restore_triggers
         {
           delete it;
           delete dbit;
-          fatal_error(ER_BACKUP_CANT_RESTORE_TRIGGER,obj->describe(buf));
-          DBUG_RETURN(m_error);
+          int err= report_error(ER_BACKUP_CANT_RESTORE_TRIGGER,
+                                obj->describe(buf));
+          DBUG_RETURN(fatal_error(err));
         }
         break;
 
@@ -1188,8 +1160,8 @@ int Backup_restore_ctx::restore_triggers
   while ((ev= it++)) 
     if (ev->m_obj_ptr->execute(m_thd))
     {
-      fatal_error(ER_BACKUP_CANT_RESTORE_EVENT,ev->describe(buf));
-      DBUG_RETURN(m_error);
+      int ret= report_error(ER_BACKUP_CANT_RESTORE_EVENT,ev->describe(buf));
+      DBUG_RETURN(fatal_error(ret));
     };
 
   DBUG_RETURN(0);
@@ -1228,18 +1200,21 @@ int Backup_restore_ctx::do_restore(bool 
   DBUG_PRINT("restore", ("Restoring meta-data"));
 
   // unless RESTORE... OVERWRITE: return error if database already exists
-  if (!overwrite) {
+  if (!overwrite)
+  {
     Image_info::Db_iterator *dbit= info.get_dbs();
 
-    if (!dbit) {
-      DBUG_RETURN(fatal_error(ER_OUT_OF_RESOURCES));
-    }
+    if (!dbit)
+      DBUG_RETURN(fatal_error(report_error(ER_OUT_OF_RESOURCES)));
 
     Image_info::Db *mydb;
-    while ((mydb= static_cast<Image_info::Db*>((*dbit)++))) {
-      if (!obs::check_db_existence(&mydb->name())) {
+    while ((mydb= static_cast<Image_info::Db*>((*dbit)++)))
+    {
+      if (!obs::check_db_existence(&mydb->name())) 
+      {
         delete dbit;
-        DBUG_RETURN(fatal_error(ER_RESTORE_DB_EXISTS, mydb->name().ptr()));
+        err= report_error(ER_RESTORE_DB_EXISTS, mydb->name().ptr());
+        DBUG_RETURN(fatal_error(err));
       }
     }
     delete dbit;
@@ -1247,17 +1222,17 @@ int Backup_restore_ctx::do_restore(bool 
 
   disable_fkey_constraints();                   // Never errors
 
-  if (read_meta_data(info, s))
+  err= read_meta_data(info, s);  // Can log errors via callback functions.
+  if (err)
   {
-    m_thd->main_da.reset_diagnostics_area();    // Never errors
-
-    fatal_error(ER_BACKUP_READ_META);
-    DBUG_RETURN(m_error);
+    if (!error_reported())
+      report_error(ER_BACKUP_READ_META);
+    DBUG_RETURN(fatal_error(err));
   }
 
   if (s.next_chunk() == BSTREAM_ERROR)
   {
-    DBUG_RETURN(fatal_error(ER_BACKUP_NEXT_CHUNK));
+    DBUG_RETURN(fatal_error(report_error(ER_BACKUP_NEXT_CHUNK)));
   }
 
   DBUG_PRINT("restore",("Restoring table data"));
@@ -1271,16 +1246,17 @@ int Backup_restore_ctx::do_restore(bool 
   close_thread_tables(m_thd);                   // Never errors
   m_thd->main_da.reset_diagnostics_area();      // Never errors  
 
-  if (lock_tables_for_restore())                // logs errors
-    DBUG_RETURN(m_error);
+  err= lock_tables_for_restore();               // logs errors
+  if (err)
+    DBUG_RETURN(fatal_error(err));
 
   // Here restore drivers are created to restore table data
-  err= restore_table_data(m_thd, info, s); // reports errors
+  err= restore_table_data(m_thd, info, s);      // logs errors
 
   unlock_tables();                              // Never errors
 
   if (err)
-    DBUG_RETURN(ER_BACKUP_RESTORE);
+    DBUG_RETURN(fatal_error(err));
 
   /* 
    Re-create all triggers and events (it was not done in @c bcat_create_item()).
@@ -1289,16 +1265,9 @@ int Backup_restore_ctx::do_restore(bool 
    creation of these objects will fail.
   */
 
-  if (restore_triggers_and_events())    // reports errors
-     DBUG_RETURN(ER_BACKUP_RESTORE);
-
-  DBUG_PRINT("restore",("Done."));
-
-  if (read_summary(info, s))
-  {
-    fatal_error(ER_BACKUP_READ_SUMMARY);
-    DBUG_RETURN(m_error);
-  }
+  err= restore_triggers_and_events();           // logs errors
+  if (err)
+     DBUG_RETURN(fatal_error(err));
 
   /* 
     FIXME: this call is here because object services doesn't clean the
@@ -1309,6 +1278,12 @@ int Backup_restore_ctx::do_restore(bool 
   close_thread_tables(m_thd);                   // Never errors
   m_thd->main_da.reset_diagnostics_area();      // Never errors
 
+  DBUG_PRINT("restore",("Done."));
+
+  err= read_summary(info, s);
+  if (err)
+    DBUG_RETURN(fatal_error(report_error(ER_BACKUP_READ_SUMMARY)));
+
   /*
     Report validity point time and binlog position stored in the backup image
     (in the summary section).
@@ -1326,8 +1301,7 @@ int Backup_restore_ctx::do_restore(bool 
 }
 
 /**
-  Report stream open error by calling fatal_error, effectively moving
-  context object into error state.
+  Report stream open error and move context object into error state.
   
   @return error code given as input or the one stored in the context
   object if a fatal error has already been reported.
@@ -1338,26 +1312,26 @@ int Backup_restore_ctx::report_stream_op
   int error= 0;
   switch (my_open_status) {
     case ER_OPTION_PREVENTS_STATEMENT:
-      error= fatal_error(ER_OPTION_PREVENTS_STATEMENT, "--secure-file-priv");
+      error= report_error(ER_OPTION_PREVENTS_STATEMENT, "--secure-file-priv");
       break;
     case ER_BACKUP_WRITE_LOC:
       /*
         For this error, use the actual value returned instead of the
         path complimented with backupdir.
       */
-      error= fatal_error(ER_BACKUP_WRITE_LOC, location->str);
+      error= report_error(ER_BACKUP_WRITE_LOC, location->str);
       break;
     case ER_BACKUP_READ_LOC:
       /*
         For this error, use the actual value returned instead of the
         path complimented with backupdir.
       */
-      error= fatal_error(ER_BACKUP_READ_LOC, location->str);
+      error= report_error(ER_BACKUP_READ_LOC, location->str);
       break;
     default:
       DBUG_ASSERT(FALSE);
   }
-  return error;
+  return fatal_error(error);
 }
 
 namespace backup {
@@ -1502,6 +1476,7 @@ int bcat_reset(st_bstream_image_header *
 
   DBUG_ASSERT(catalogue);
   Restore_info *info= static_cast<Restore_info*>(catalogue);
+  Logger &log= info->m_log;
 
   /*
     Iterate over the list of snapshots read from the backup image (and stored
@@ -1526,50 +1501,50 @@ int bcat_reset(st_bstream_image_header *
 
       if (!se || !hton)
       {
-        info->m_ctx.fatal_error(ER_BACKUP_CANT_FIND_SE, name_lex.str);
+        log.report_error(ER_BACKUP_CANT_FIND_SE, name_lex.str);
         return BSTREAM_ERROR;
       }
 
       if (!hton->get_backup_engine)
       {
-        info->m_ctx.fatal_error(ER_BACKUP_NO_NATIVE_BE, name_lex.str);
+        log.report_error(ER_BACKUP_NO_NATIVE_BE, name_lex.str);
         return BSTREAM_ERROR;
       }
 
-      info->m_snap[n]= new Native_snapshot(info->m_ctx, snap->version, se);
+      info->m_snap[n]= new Native_snapshot(log, snap->version, se);
                                                               // reports errors
       break;
     }
 
     case BI_NODATA:
-      info->m_snap[n]= new Nodata_snapshot(info->m_ctx, snap->version);
+      info->m_snap[n]= new Nodata_snapshot(log, snap->version);
                                                               // reports errors
       break;
 
     case BI_CS:
-      info->m_snap[n]= new CS_snapshot(info->m_ctx, snap->version);
+      info->m_snap[n]= new CS_snapshot(log, snap->version);
                                                               // reports errors
       break;
 
     case BI_DEFAULT:
-      info->m_snap[n]= new Default_snapshot(info->m_ctx, snap->version);
+      info->m_snap[n]= new Default_snapshot(log, snap->version);
                                                               // reports errors
       break;
 
     default:
       // note: we use convention that snapshots are counted starting from 1.
-      info->m_ctx.fatal_error(ER_BACKUP_UNKNOWN_BE, n + 1);
+      log.report_error(ER_BACKUP_UNKNOWN_BE, n + 1);
       return BSTREAM_ERROR;
     }
 
     if (!info->m_snap[n])
     {
-      info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+      log.report_error(ER_OUT_OF_RESOURCES);
       return BSTREAM_ERROR;
     }
 
     info->m_snap[n]->m_num= n + 1;
-    info->m_ctx.report_driver(info->m_snap[n]->name());
+    log.report_driver(info->m_snap[n]->name());
   }
 
   return BSTREAM_OK;
@@ -1599,6 +1574,7 @@ int bcat_add_item(st_bstream_image_heade
   using namespace backup;
 
   Restore_info *info= static_cast<Restore_info*>(catalogue);
+  Logger &log= info->m_log;
 
   backup::String name_str(item->name.begin, item->name.end);
 
@@ -1639,7 +1615,7 @@ int bcat_add_item(st_bstream_image_heade
         with error earlier.
        */
       DBUG_ASSERT(it->snap_num >= info->snap_count());
-      info->m_ctx.fatal_error(ER_BACKUP_WRONG_TABLE_BE, it->snap_num + 1);
+      log.report_error(ER_BACKUP_WRONG_TABLE_BE, it->snap_num + 1);
       return BSTREAM_ERROR;
     }
 
@@ -1703,6 +1679,7 @@ void* bcat_iterator_get(st_bstream_image
   DBUG_ASSERT(catalogue);
 
   Backup_info *info= static_cast<Backup_info*>(catalogue);
+  backup::Logger &log= info->m_log;
 
   switch (type) {
 
@@ -1721,7 +1698,7 @@ void* bcat_iterator_get(st_bstream_image
     Iterator *it= info->get_tablespaces();
     if (!it) 
     {
-      info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+      log.report_error(ER_OUT_OF_RESOURCES);
       return NULL;
     }
   
@@ -1733,7 +1710,7 @@ void* bcat_iterator_get(st_bstream_image
     Iterator *it= info->get_dbs();
     if (!it) 
     {
-      info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+      log.report_error(ER_OUT_OF_RESOURCES);
       return NULL;
     }
 
@@ -1746,7 +1723,7 @@ void* bcat_iterator_get(st_bstream_image
   
     if (!it)
     {
-      info->m_ctx.fatal_error(ER_BACKUP_CAT_ENUM);
+      log.report_error(ER_BACKUP_CAT_ENUM);
       return NULL;
     }
 
@@ -1837,18 +1814,19 @@ void* bcat_db_iterator_get(st_bstream_im
   DBUG_ASSERT(dbi);
   
   Backup_info *info= static_cast<Backup_info*>(catalogue);
+  backup::Logger &log= info->m_log;
   Backup_info::Db *db = info->get_db(dbi->base.pos);
 
   if (!db)
   {
-    info->m_ctx.fatal_error(ER_BACKUP_UNKNOWN_OBJECT);
+    log.report_error(ER_BACKUP_UNKNOWN_OBJECT);
     return NULL;
   }
 
   backup::Image_info::Iterator *it= info->get_db_objects(*db);
   if (!it)
   {
-    info->m_ctx.fatal_error(ER_OUT_OF_RESOURCES);
+    log.report_error(ER_OUT_OF_RESOURCES);
     return NULL;
   }
 
@@ -1901,7 +1879,8 @@ int bcat_create_item(st_bstream_image_he
   DBUG_ASSERT(item);
 
   Restore_info *info= static_cast<Restore_info*>(catalogue);
-  THD *thd= info->m_ctx.thd();
+  Logger &log= info->m_log;
+  THD *thd= info->m_thd;
   int create_err= 0;
 
   switch (item->type) {
@@ -1923,7 +1902,7 @@ int bcat_create_item(st_bstream_image_he
   */
 
   default:
-    info->m_ctx.fatal_error(ER_BACKUP_UNKNOWN_OBJECT_TYPE);
+    log.report_error(ER_BACKUP_UNKNOWN_OBJECT_TYPE);
     return BSTREAM_ERROR;    
   }
 
@@ -1931,7 +1910,7 @@ int bcat_create_item(st_bstream_image_he
 
   if (!obj)
   {
-    info->m_ctx.fatal_error(ER_BACKUP_UNKNOWN_OBJECT);
+    log.report_error(ER_BACKUP_UNKNOWN_OBJECT);
     return BSTREAM_ERROR;
   }
 
@@ -1950,7 +1929,7 @@ int bcat_create_item(st_bstream_image_he
 
   if (!sobj)
   {
-    info->m_ctx.fatal_error(create_err, desc);
+    log.report_error(create_err, desc);
     return BSTREAM_ERROR;
   }
 
@@ -1992,7 +1971,7 @@ int bcat_create_item(st_bstream_image_he
     if (ts)
     {
       DBUG_PRINT("restore",(" tablespace has changed on the server - aborting"));
-      info->m_ctx.fatal_error(ER_BACKUP_TS_CHANGE, desc);
+      log.report_error(ER_BACKUP_TS_CHANGE, desc);
       delete ts;
       return BSTREAM_ERROR;
     }
@@ -2015,9 +1994,9 @@ int bcat_create_item(st_bstream_image_he
     */
     if (!obs::check_user_existence(thd, sobj->get_name()))
     {
-      info->m_ctx.report_error(log_level::WARNING, 
-                               ER_BACKUP_GRANT_SKIPPED,
-                               create_stmt);
+      log.report_error(log_level::WARNING, 
+                       ER_BACKUP_GRANT_SKIPPED, 
+                       create_stmt);
       return BSTREAM_OK; 
     }
     /*
@@ -2037,14 +2016,14 @@ int bcat_create_item(st_bstream_image_he
     db_name.append(start, size);
     if (!info->has_db(db_name))
     {
-      info->m_ctx.fatal_error(ER_BACKUP_GRANT_WRONG_DB, create_stmt);
+      log.report_error(ER_BACKUP_GRANT_WRONG_DB, create_stmt);
       return BSTREAM_ERROR;
     }
   }
 
   if (sobj->execute(thd))
   {
-    info->m_ctx.fatal_error(create_err, desc);
+    log.report_error(create_err, desc);
     return BSTREAM_ERROR;
   }
   
@@ -2115,11 +2094,12 @@ int bcat_get_item_create_query(st_bstrea
   ::String *buf= &(info->serialization_buf);
   buf->length(0);
 
-  if (obj->m_obj_ptr->serialize(info->m_ctx.thd(), buf))
+  if (obj->m_obj_ptr->serialize(info->m_thd, buf))
   {
     Image_info::Obj::describe_buf dbuf;
 
-    info->m_ctx.fatal_error(meta_err, obj->describe(dbuf));
+    info->m_log.report_error(meta_err, obj->describe(dbuf));
+
     return BSTREAM_ERROR;    
   }
 

=== modified file 'sql/backup/logger.cc'
--- a/sql/backup/logger.cc	2008-10-27 13:06:21 +0000
+++ b/sql/backup/logger.cc	2008-11-25 17:44:19 +0000
@@ -28,15 +28,27 @@ namespace backup {
   the moment. Destinations which are not ready/initialized yet should be 
   silently ignored.
 
-  @returns 0 on success.
+  @returns Reported error code.
  */
 int Logger::write_message(log_level::value level, int error_code,
                           const char *msg)
 {
    char buf[ERRMSGSIZE + 30];
+   /*
+     When logging to server's error log, msg will be prefixed with
+     "Backup:"/"Restore:" if the operation has been initialized (i.e., after
+     Logger::init() call). For other destinations, msg is reported as it is.
+     
+     Pointer out points at output string for server's error log, which has the
+     prefix added if needed.
+    */ 
    const char *out= msg;
 
-   if (m_state == READY || m_state == RUNNING)
+   /*
+     Note: m_type is meaningful only after a call to init() i.e., 
+     if m_state != CREATED.
+   */ 
+   if (m_state != CREATED)
    {
      my_snprintf(buf, sizeof(buf), "%s: %s", 
                  m_type == BACKUP ? "Backup" : "Restore" , msg);
@@ -45,43 +57,61 @@ int Logger::write_message(log_level::val
    
    switch (level) {
    case log_level::ERROR:
-     if (m_save_errors)
-     {
-       error.code= error_code;
-       error.level= MYSQL_ERROR::WARN_LEVEL_ERROR;
-       error.msg= sql_strdup(msg);
-     }
+   {
+     // Report to server's error log
 
      sql_print_error(out);
-     if (m_push_errors)
-       push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-			   error_code, msg);
-     DBUG_PRINT("backup_log",("[ERROR] %s", out));
-     
+
+     // Report to the client
+
+     bool saved_value= m_thd->no_warnings_for_error;
+     m_thd->no_warnings_for_error= m_push_errors ? FALSE : TRUE;
+     my_printf_error(error_code, msg, MYF(0));
+     m_thd->no_warnings_for_error= saved_value;
+ 
+     m_error_reported= TRUE;
+
+     // Report to backup logs
+
      if (m_state == READY || m_state == RUNNING)
      {
        time_t ts = my_time(0);
 
        backup_log->error_num(error_code);
-       backup_log->write_progress(0, ts, ts, 0, 0, error_code, out);
+       backup_log->write_progress(0, ts, ts, 0, 0, error_code, msg);
      }
      
-     return 0;
+     // Report in the debug trace
+     
+     DBUG_PRINT("backup_log",("[ERROR] %s", out));
+     
+     return error_code;
+   }
 
    case log_level::WARNING:
+     // Report to server's error log
      sql_print_warning(out);
+     
+     // Report to the client (push on warning stack)
      if (m_push_errors)
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                            error_code, msg);
+
+     // Report to the debug trace
      DBUG_PRINT("backup_log",("[Warning] %s", out));
-     return 0;
+
+     return error_code;
 
    case log_level::INFO:
+     // Report to server's error log
      sql_print_information(out);
+
+     // Report to the debug trace
      DBUG_PRINT("backup_log",("[Info] %s", out));
-     return 0;
 
-   default: return ERROR;
+     return error_code;
+
+   default: DBUG_ASSERT(0); return ERROR;
    }
 }
 
@@ -94,7 +124,7 @@ int Logger::write_message(log_level::val
   If the message contains placeholders, additional arguments provide
   values to be put there.
 
-  @returns 0 on success.
+  @returns Reported error code.
  */
 int Logger::v_report_error(log_level::value level, int error_code, va_list args)
 {

=== modified file 'sql/backup/logger.h'
--- a/sql/backup/logger.h	2008-11-14 15:02:10 +0000
+++ b/sql/backup/logger.h	2008-11-25 17:44:19 +0000
@@ -51,6 +51,7 @@ class Logger
    int report_error(log_level::value level, int error_code, ...);
    int report_error(const char *format, ...);
    int write_message(log_level::value level, const char *msg, ...);
+   int log_error(int error_code, ...);
 
    void report_start(time_t);
    void report_stop(time_t, bool);
@@ -68,11 +69,8 @@ class Logger
      return backup_log->get_backup_id(); 
    }
    
-   void save_errors();
-   void stop_save_errors();
-   void clear_saved_errors();
-   util::SAVED_MYSQL_ERROR *last_saved_error();
    bool push_errors(bool);
+   bool error_reported() const;
 
  protected:
 
@@ -84,30 +82,26 @@ class Logger
   int write_message(log_level::value level , int error_code, const char *msg);
 
  private:
+
   // Prevent copying/assigments
   Logger(const Logger&);
   Logger& operator=(const Logger&);
 
-  util::SAVED_MYSQL_ERROR error;   ///< Used to store saved errors.
-  bool m_save_errors;        ///< Flag telling if errors should be saved.
   bool m_push_errors;        ///< Should errors be pushed on warning stack?
+  bool m_error_reported;     ///< Has any error been reported?
 
   Backup_log *backup_log;    ///< Backup log interface class.
 };
 
 inline
 Logger::Logger(THD *thd) 
-  :m_type(BACKUP), m_state(CREATED),
-   m_thd(thd), m_save_errors(FALSE), m_push_errors(TRUE), backup_log(0)
-{
-  clear_saved_errors();
-}
- 
+   :m_type(BACKUP), m_state(CREATED), m_thd(thd), m_push_errors(TRUE), 
+    m_error_reported(FALSE), backup_log(0)
+{}
 
 inline
 Logger::~Logger()
 {
-  clear_saved_errors();
   delete backup_log;
 }
 
@@ -163,37 +157,20 @@ int Logger::report_error(const char *for
   return res;
 }
 
-///  Request that all reported errors are saved in the logger.
-inline
-void Logger::save_errors()
-{
-  if (m_save_errors)
-    return;
-  clear_saved_errors();
-  m_save_errors= TRUE;
-}
-
-/// Stop saving errors.
+/// Reports error without pushing it on server's error stack.
 inline
-void Logger::stop_save_errors()
+int Logger::log_error(int error_code, ...)
 {
-  if (!m_save_errors)
-    return;
-  m_save_errors= FALSE;
-}
+  va_list args;
+  bool    saved= push_errors(FALSE);
+  
+  va_start(args, error_code);
+  int res= v_report_error(log_level::ERROR, error_code, args);
+  va_end(args);
 
-/// Delete all saved errors to free resources.
-inline
-void Logger::clear_saved_errors()
-{
-  memset(&error, 0, sizeof(error));
-}
+  push_errors(saved);
 
-/// Return a pointer to most recent saved error.
-inline
-util::SAVED_MYSQL_ERROR *Logger::last_saved_error()
-{ 
-  return error.code ? &error : NULL;
+  return res;
 }
 
 /// Report start of an operation.
@@ -328,7 +305,7 @@ void Logger::report_backup_file(char *pa
     
   @returns 0 on success, error code otherwise.
 
-  @todo Decide what to do if @c initialize() signals errors.
+  @todo Detect, log and report errors to the caller.
   @todo Add code to get the user comment from command.
 */ 
 inline
@@ -338,13 +315,20 @@ int Logger::init(enum_type type, const c
     return 0;
 
   m_type= type;
-  m_state= READY;
+  mysql_reset_errors(m_thd, 0);                 // Never errors
   backup_log = new Backup_log(m_thd, (enum_backup_operation)type, query);
   backup_log->state(BUP_STARTING);
+  m_state= READY;
   DEBUG_SYNC(m_thd, "after_backup_log_init");
   return 0;
 }
 
+inline
+bool Logger::error_reported() const
+{
+  return m_error_reported;
+}
+
 } // backup namespace
 
 #endif

=== modified file 'sql/backup/restore_info.h'
--- a/sql/backup/restore_info.h	2008-11-13 13:02:36 +0000
+++ b/sql/backup/restore_info.h	2008-11-25 17:44:19 +0000
@@ -33,9 +33,8 @@ class Restore_info: public backup::Image
 {
  public:
 
-  Backup_restore_ctx &m_ctx;
+  backup::Logger &m_log;
 
-  Restore_info(Backup_restore_ctx&);
   ~Restore_info();
 
   bool is_valid() const;
@@ -47,19 +46,32 @@ class Restore_info: public backup::Image
 
  private:
 
+  /*
+    Note: constructor is private because instances of this class are supposed
+    to be created only with Backup_restore_ctx::prepare_for_restore() method.
+  */
+  Restore_info(backup::Logger&, THD*);
+
   // Prevent copying/assignments
   Restore_info(const Restore_info&);
   Restore_info& operator=(const Restore_info&);
 
+  THD *m_thd;
+
   friend int backup::restore_table_data(THD*, Restore_info&, 
                                         backup::Input_stream&);
   friend int ::bcat_add_item(st_bstream_image_header*,
                              struct st_bstream_item_info*);
+  friend int ::bcat_create_item(st_bstream_image_header *catalogue,
+                                struct st_bstream_item_info *item,
+                                bstream_blob create_stmt,
+                                bstream_blob other_meta_data);
+  friend class Backup_restore_ctx;    // Needs access to the constructor.
 };
 
 inline
-Restore_info::Restore_info(Backup_restore_ctx &ctx)
-  :m_ctx(ctx)
+Restore_info::Restore_info(backup::Logger &log, THD *thd)
+  :m_log(log), m_thd(thd)
 {}
 
 inline
@@ -86,7 +98,7 @@ Restore_info::add_ts(const ::String &nam
   Ts *ts= Image_info::add_ts(name, pos);
 
   if (!ts)
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_TS, name.ptr());
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_TS, name.ptr());
 
   return ts;
 }
@@ -99,7 +111,7 @@ Restore_info::add_db(const ::String &nam
   Db *db= Image_info::add_db(name, pos);
 
   if (!db)
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_DB, name.ptr());
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_DB, name.ptr());
 
   return db;
 }
@@ -113,7 +125,7 @@ Restore_info::add_table(Image_info::Db &
   Table *t= Image_info::add_table(db, name, snap, pos);
 
   if (!t)
-    m_ctx.fatal_error(ER_BACKUP_CATALOG_ADD_TABLE, db.name().ptr(), name.ptr());
+    m_log.report_error(ER_BACKUP_CATALOG_ADD_TABLE, db.name().ptr(), name.ptr());
 
   return t;
 }

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-11-19 22:08:05 +0000
+++ b/sql/share/errmsg.txt	2008-11-26 10:05:19 +0000
@@ -6436,3 +6436,5 @@ ER_RESTORE_DB_EXISTS
   eng "Database \'%-.64s\' already exists. Use OVERWRITE flag to overwrite."
 ER_QUERY_CACHE_DISABLED
 	eng "Query cache is disabled; restart the server with query_cache_type=1 to enable it"
+ER_BACKUP_UNEXPECTED_DATA
+  eng "Backup image contains no tables, but table data was found in it"

=== modified file 'sql/si_logs.h'
--- a/sql/si_logs.h	2008-10-30 17:53:24 +0000
+++ b/sql/si_logs.h	2008-11-14 14:49:09 +0000
@@ -201,7 +201,7 @@ void Backup_log::stop(time_t when)
 inline
 void Backup_log::binlog_file(char *file)
 {
-  if (strlen(file) > 0)
+  if (file && strlen(file) > 0)
     m_op_hist.binlog_file= file;
 }
 
@@ -217,7 +217,7 @@ void Backup_log::binlog_file(char *file)
 inline
 void Backup_log::master_binlog_file(char *file)
 {
-  if (strlen(file) > 0)
+  if (file && strlen(file) > 0)
     m_op_hist.master_binlog_file= file;
 }
 

Thread
bzr commit into mysql-6.0 branch (jorgen.loland:2729) Jorgen Loland28 Nov