MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Rafal Somla Date:October 31 2008 3:25pm
Subject:bzr commit into mysql-6.0 branch (Rafal.Somla:2717) Bug#33567 Bug#34480
Bug#36933
View as plain text  
#At file:///ext/mysql/bzr/backup/bug36933/

 2717 Rafal Somla	2008-10-31
      BUG#36933, BUG#34480, BUG#33567 (Backup: snapshot error + crash if double 
      backup)
      
      Before: When user specified the same database twice in the BACKUP DATABASE 
      statement, it was included twice in the backup image. This lead to a host 
      of problems.
      
      After: 
      
      1. Parser reports error if the same database repeated twice in the list (similar 
      as for other SQL statements, e.g., DROP TABLE).
      
      2. Backup kernel code will ignore duplicates in the database list (if they ever
      get there) and never try to backup the same database twice.
modified:
  mysql-test/suite/backup/r/backup.result
  mysql-test/suite/backup/r/backup_errors.result
  mysql-test/suite/backup/t/backup.test
  mysql-test/suite/backup/t/backup_errors.test
  sql/backup/backup_info.cc
  sql/backup/image_info.cc
  sql/backup/image_info.h
  sql/share/errmsg.txt
  sql/sql_lex.cc
  sql/sql_lex.h
  sql/sql_yacc.yy

per-file messages:
  mysql-test/suite/backup/t/backup.test
    1. Use @@backupdir when constructing paths to backup images.
    
    2. Check the scenario reported in bugs: if BACKUP would include a table with 
    blobs and primary key twice into backup image then RESTORE should fail.
  mysql-test/suite/backup/t/backup_errors.test
    Trigger the ER_NONUNIQ_DB error.
  sql/backup/backup_info.cc
    When iterating over the list of databases specified for backup, ignore repeated names.
  sql/backup/image_info.cc
    Mark has_db() method as const.
  sql/backup/image_info.h
    Mark has_db() method as const.
  sql/share/errmsg.txt
    Add ER_NONUNIQ_DB error analogous to ER_NONUNIQ_TABLE.
  sql/sql_lex.cc
    Implement LEX::add_db_to_list() method which checks for duplicates.
  sql/sql_lex.h
    Add to LEX methods for populating the list of databases.
  sql/sql_yacc.yy
    Use the new LEX methods for populating db list and abort parsing on error 
    (e.g. when database name repeated twice).
=== modified file 'mysql-test/suite/backup/r/backup.result'
--- a/mysql-test/suite/backup/r/backup.result	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/r/backup.result	2008-10-31 15:25:00 +0000
@@ -172,7 +172,7 @@ PRIMARY KEY (`a`)
 ) ENGINE=INNODB DEFAULT CHARSET=latin1;
 CREATE TABLE bup_default.t1 (a int) engine=innodb;
 CREATE TABLE bup_default.t2 (a int) engine=MYISAM;
-CREATE TABLE bup_default.t1_blob (a int, b text) engine=innodb;
+CREATE TABLE bup_default.t1_blob (a int, b text, primary key (a)) engine=innodb;
 INSERT INTO bup_default.wide VALUES (
 NULL,
 "This is column b pass 01",

=== modified file 'mysql-test/suite/backup/r/backup_errors.result'
--- a/mysql-test/suite/backup/r/backup_errors.result	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/r/backup_errors.result	2008-10-31 15:25:00 +0000
@@ -20,6 +20,8 @@ BACKUP DATABASE foo TO 'test.bak';
 ERROR 42000: Unknown database 'foo'
 BACKUP DATABASE test,foo,bdb,bar TO 'test.bak';
 ERROR 42000: Unknown database 'foo,bar'
+BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
+ERROR 42000: Not unique database: 'foo'
 use adb;
 create table t1 (a int);
 create procedure p1() backup database test to 'test.bak';

=== modified file 'mysql-test/suite/backup/t/backup.test'
--- a/mysql-test/suite/backup/t/backup.test	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/t/backup.test	2008-10-31 15:25:00 +0000
@@ -3,6 +3,7 @@
 --source include/have_debug_sync.inc
 --source include/have_log_bin.inc
 
+let $bdir=`SELECT @@backupdir`;
 SET DEBUG_SYNC= 'RESET';
 
 connect (backup,localhost,root,,);
@@ -15,7 +16,7 @@ DROP DATABASE IF EXISTS db1;
 DROP DATABASE IF EXISTS db2;
 DROP DATABASE IF EXISTS db3;
 --error 0,1
---remove_file $MYSQLTEST_VARDIR/master-data/bup_default.bak
+--remove_file $bdir/bup_default.bak
 --enable_warnings
 
 CREATE DATABASE db1;
@@ -154,7 +155,7 @@ RESTORE FROM 'test.ba';
 # determine id of RESTORE operation
 SELECT MAX(backup_id) FROM mysql.backup_history INTO @bid;
 
---remove_file $MYSQLTEST_VARDIR/master-data/test.ba
+--remove_file $bdir/test.ba
 
 SHOW CREATE DATABASE db1;
 SHOW CREATE DATABASE db2;
@@ -229,7 +230,7 @@ CREATE TABLE bup_default.wide (
 
 CREATE TABLE bup_default.t1 (a int) engine=innodb;
 CREATE TABLE bup_default.t2 (a int) engine=MYISAM;
-CREATE TABLE bup_default.t1_blob (a int, b text) engine=innodb;
+CREATE TABLE bup_default.t1_blob (a int, b text, primary key (a)) engine=innodb;
 
 # Insert some data.
 
@@ -327,9 +328,44 @@ SELECT COUNT(*) FROM bup_default.t1_blob
 SELECT COUNT(*) FROM bup_default.wide;
 --query_vertical SELECT * FROM bup_default.wide;
 
+#
+# First, check that BACKUP/RESTORE doesn't get confused when the same 
+# database is repeated twice (BUG#36933, BUG#34480, BUG#33567).
+#
+
+# Try to backup the same database twice. We arrange things so that if this
+# BACKUP statement succeeds (it should not) then the resulting image will
+# be used by the following restore to check how it handles it (it should fail).
+#
+# We take care to ensure that the result file looks the same, regardless of 
+# whether this BACKUP fails or not. This way, in both cases MTR will continue 
+# and execute the following RESTORE statement.
+#
+--disable_query_log
+--error 0, ER_NONUNIQ_DB
+BACKUP DATABASE bup_default, bup_default TO "bup_default1.bak";
+--enable_query_log
+
+# see if last BACKUP triggered any errors (it should).
+let $errors=`SHOW ERRORS`;
+
+# Now backup bup_default for real
 --replace_column 1 #
 BACKUP DATABASE bup_default TO "bup_default.bak";
 
+#
+# In case BACKUP of double database succeeded, use the backup image from
+# that operation - later RESTORE should fail miserably...
+#
+if (!$errors)
+{
+--move_file $bdir/bup_default1.bak $bdir/bup_default.bak
+}
+
+# clean the bup_default1.bak file if it still exists
+--error 0,1
+--remove_file $bdir/bup_default1.bak
+
 # Now restore the database and then check to make sure the data is there.
 
 DROP DATABASE bup_default;
@@ -375,7 +411,7 @@ SELECT * FROM bup_default.t2;
 SELECT COUNT(*) FROM bup_default.t1_blob;
 SELECT COUNT(*) FROM bup_default.wide;
 
---remove_file $MYSQLTEST_VARDIR/master-data/bup_default.bak
+--remove_file $bdir/bup_default.bak
 --replace_column 1 #
 BACKUP DATABASE bup_default TO 'bup_default.bak';
 
@@ -493,9 +529,9 @@ DROP DATABASE IF EXISTS bup_delete;
 DROP DATABASE IF EXISTS bup_default;
 --enable_warnings
 
---remove_file $MYSQLTEST_VARDIR/master-data/bup_delete.bak
---remove_file $MYSQLTEST_VARDIR/master-data/bup_default_timestamp.bak
---remove_file $MYSQLTEST_VARDIR/master-data/bup_default.bak
+--remove_file $bdir/bup_delete.bak
+--remove_file $bdir/bup_default_timestamp.bak
+--remove_file $bdir/bup_default.bak
 --error 0,1
---remove_file $MYSQLTEST_VARDIR/master-data/test.ba
+--remove_file $bdir/test.ba
 

=== modified file 'mysql-test/suite/backup/t/backup_errors.test'
--- a/mysql-test/suite/backup/t/backup_errors.test	2008-10-07 17:15:44 +0000
+++ b/mysql-test/suite/backup/t/backup_errors.test	2008-10-31 15:25:00 +0000
@@ -50,6 +50,10 @@ BACKUP DATABASE foo TO 'test.bak';
 -- error ER_BAD_DB_ERROR
 BACKUP DATABASE test,foo,bdb,bar TO 'test.bak';
 
+# repeated database
+-- error ER_NONUNIQ_DB
+BACKUP DATABASE foo,test,bar,foo TO 'test.bak';
+
 # Test that BACKUP/RESTORE statements are disable inside stored routines,
 # triggers and events.
 

=== modified file 'sql/backup/backup_info.cc'
--- a/sql/backup/backup_info.cc	2008-10-24 08:11:18 +0000
+++ b/sql/backup/backup_info.cc	2008-10-31 15:25:00 +0000
@@ -543,6 +543,10 @@ int Backup_info::add_dbs(List< ::LEX_STR
   while ((s= it++))
   {
     backup::String db_name(*s);
+
+    // Ignore the database if it has already been inserted into the catalogue.    
+    if (has_db(db_name))
+      continue;
     
     if (is_internal_db_name(&db_name))
     {

=== modified file 'sql/backup/image_info.cc'
--- a/sql/backup/image_info.cc	2008-10-14 12:08:56 +0000
+++ b/sql/backup/image_info.cc	2008-10-31 15:25:00 +0000
@@ -206,7 +206,7 @@ int Image_info::add_snapshot(Snapshot_in
 /**
   Check if catalogue contains given database.
  */ 
-bool Image_info::has_db(const String &db_name)
+bool Image_info::has_db(const String &db_name) const
 {
   for (uint n=0; n < m_dbs.count() ; ++n)
     if (m_dbs[n] && m_dbs[n]->name() == db_name)

=== modified file 'sql/backup/image_info.h'
--- a/sql/backup/image_info.h	2008-10-15 15:38:28 +0000
+++ b/sql/backup/image_info.h	2008-10-31 15:25:00 +0000
@@ -83,7 +83,7 @@ public: // public interface
 
    // Examine contents of the catalogue.
 
-   bool has_db(const String&);
+   bool has_db(const String&) const;
 
    // Retrieve objects using their coordinates.
 

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-10-15 06:48:36 +0000
+++ b/sql/share/errmsg.txt	2008-10-31 15:25:00 +0000
@@ -6405,3 +6405,5 @@ ER_BACKUP_BINLOG
         nor "Lesing av binlog feilet under BACKUP"
         norwegian-ny "Lesing av binlog feila under BACKUP"
 
+ER_NONUNIQ_DB 42000 S1009
+        eng "Not unique database: '%-.192s'"

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2008-10-07 22:05:23 +0000
+++ b/sql/sql_lex.cc	2008-10-31 15:25:00 +0000
@@ -3022,3 +3022,28 @@ bool LEX::is_partition_management() cons
            alter_info.flags == ALTER_REORGANIZE_PARTITION));
 }
 
+int LEX::add_db_to_list(LEX_STRING *name)
+{
+  DBUG_ASSERT(name);
+    
+  List_iterator<LEX_STRING> it(db_list);
+  LEX_STRING *copy;
+  
+  while ((copy= it++))
+   if (!my_strnncoll(system_charset_info, 
+                     (const uchar*) name->str, name->length , 
+                     (const uchar*) copy->str, copy->length ))
+   {    
+     my_error(ER_NONUNIQ_DB, MYF(0), name->str);
+     return ER_NONUNIQ_DB;
+   }
+
+  copy= (LEX_STRING*) sql_memdup(name, sizeof(LEX_STRING));
+  if (copy == NULL)
+    return ER_OUT_OF_RESOURCES;
+    
+  if (db_list.push_back(copy))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-10-07 22:05:23 +0000
+++ b/sql/sql_lex.h	2008-10-31 15:25:00 +0000
@@ -1875,6 +1875,13 @@ struct LEX: public Query_tables_list
     }
     return FALSE;
   }
+
+  void clear_db_list()
+  {
+    db_list.empty();
+  }
+
+  int add_db_to_list(LEX_STRING *name);
 };
 
 

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-10-02 14:03:57 +0000
+++ b/sql/sql_yacc.yy	2008-10-31 15:25:00 +0000
@@ -6422,8 +6422,6 @@ slave_until_opts:
 
 restore:
           RESTORE_SYM
-          FROM
-          TEXT_STRING_sys
           {
             LEX *lex= Lex;
             if (lex->sphead)
@@ -6432,18 +6430,17 @@ restore:
               MYSQL_YYABORT;
             }
             lex->sql_command = SQLCOM_RESTORE;
-            lex->db_list.empty();
-            lex->backup_dir = $3; 
+            lex->clear_db_list();
+          }
+          FROM
+          TEXT_STRING_sys
+          {
+            Lex->backup_dir = $4; 
           }
         ;
 
-backup:
-          BACKUP_SYM
-          DATABASE
-          database_list
-          TO_SYM
-          TEXT_STRING_sys
-          opt_compression
+backup:   
+          BACKUP_SYM 
           {
             LEX *lex= Lex;
             if (lex->sphead)
@@ -6452,7 +6449,15 @@ backup:
               MYSQL_YYABORT;
             }
             lex->sql_command = SQLCOM_BACKUP;
-            lex->backup_dir = $5; 
+            lex->clear_db_list();
+          }
+          DATABASE
+          database_list 
+          TO_SYM 
+          TEXT_STRING_sys
+          opt_compression
+          {
+            Lex->backup_dir = $6;
           }
         | BACKUP_TEST_SYM
           database_list
@@ -6485,29 +6490,19 @@ opt_compression_algorithm:
 
 database_list:
           '*'
-          {
-            Lex->db_list.empty();
-          }
+          {}
         | database_ident_list
         ;
 
 database_ident_list:
           ident
           {
-            LEX *lex= Lex;
-            LEX_STRING* ls= (LEX_STRING*) sql_memdup(&$1, sizeof(LEX_STRING));
-            if (ls == NULL)
-              MYSQL_YYABORT;
-            lex->db_list.empty();
-            if (lex->db_list.push_back(ls))
+            if (Lex->add_db_to_list(&$1))
               YYABORT;
           }
         | database_ident_list ',' ident
           {
-            LEX_STRING *ls= (LEX_STRING*) sql_memdup(&$3, sizeof(LEX_STRING));
-            if (ls == NULL)
-              MYSQL_YYABORT;
-            if (Lex->db_list.push_back(ls))
+            if (Lex->add_db_to_list(&$3))
               YYABORT;
           }
         ;

Thread
bzr commit into mysql-6.0 branch (Rafal.Somla:2717) Bug#33567 Bug#34480Bug#36933Rafal Somla31 Oct
  • Re: bzr commit into mysql-6.0 branch (Rafal.Somla:2717) Bug#33567Bug#34480 Bug#36933Øystein Grøvlen4 Nov
    • Re: bzr commit into mysql-6.0 branch (Rafal.Somla:2717) Bug#33567Bug#34480 Bug#36933Rafal Somla4 Nov
      • Re: bzr commit into mysql-6.0 branch (Rafal.Somla:2717) Bug#33567Bug#34480 Bug#36933Øystein Grøvlen4 Nov