List:Commits« Previous MessageNext Message »
From:Chuck Bell Date:March 1 2010 9:31pm
Subject:bzr commit into mysql-6.0-codebase-bugfixing branch
(charles.bell:3836) Bug#50357
View as plain text  
#At file:///Users/cbell/source/bzr/mysql-6.0-review/ based on revid:charles.bell@stripped

 3836 Chuck Bell	2010-03-01
      BUG#50357 : Innodb blob+text columns: empty strings become NULL after restore
      
      If an InnoDB table with zero length blob fields is backed up and
      restored, the fields are set to NULL instead of the empty string.
      
      This patch corrects the behavior by recording the NULL status
      during backup and applying it on restore.
      
      original changeset: 3132 (mysql-backup-backport)
     @ mysql-test/suite/backup/r/backup_blob.result
        Corrected result file.
     @ mysql-test/suite/backup/t/backup_blob.test
        Added test case for checking NULL status after restore for zero
        length blob fields.
     @ sql/backup/be_default.cc
        Added a check for saving NULL status during backup.
        Added a check to setting NULL status during restore.
     @ sql/backup/be_default.h
        Added status indicators.

    modified:
      mysql-test/suite/backup/r/backup_blob.result
      mysql-test/suite/backup/t/backup_blob.test
      sql/backup/be_default.cc
      sql/backup/be_default.h
=== modified file 'mysql-test/suite/backup/r/backup_blob.result'
Binary files a/mysql-test/suite/backup/r/backup_blob.result	2010-02-24 22:16:05 +0000 and b/mysql-test/suite/backup/r/backup_blob.result	2010-03-01 21:31:43 +0000 differ

=== modified file 'mysql-test/suite/backup/t/backup_blob.test'
--- a/mysql-test/suite/backup/t/backup_blob.test	2010-02-24 22:16:05 +0000
+++ b/mysql-test/suite/backup/t/backup_blob.test	2010-03-01 21:31:43 +0000
@@ -92,19 +92,32 @@ CREATE TABLE mydb.mytbl2 (
   f10 longtext
 ) ENGINE INNODB;
 
+CREATE TABLE mydb.mytbl3 (
+   f1 char(10),
+   f2 varchar(10), 
+   f3 binary(10), 
+   f4 varbinary(10), 
+   f5 blob, 
+   f6 text
+) ENGINE INNODB;
+
+
 --echo #
 --echo # Insert some data.
 --echo #
 INSERT INTO mydb.mytbl1 
-  values (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+  VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO mydb.mytbl2 
-  values (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+  VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+INSERT INTO mydb.mytbl3 
+  VALUES ('','','','','','');
 
 --echo # 
---echo # Show valus from the tables.
+--echo # Show values from the tables before restore.
 --echo #
 SELECT * FROM mydb.mytbl1;
 SELECT * FROM mydb.mytbl2;
+SELECT * FROM mydb.mytbl3;
 
 --replace_column 1 #
 BACKUP DATABASE mydb TO 'mydb.bak';
@@ -113,10 +126,11 @@ BACKUP DATABASE mydb TO 'mydb.bak';
 RESTORE FROM 'mydb.bak' OVERWRITE;
 
 --echo # 
---echo # Show valus from the tables.
+--echo # Show values from the tables after restore.
 --echo #
 SELECT * FROM mydb.mytbl1;
 SELECT * FROM mydb.mytbl2;
+SELECT * FROM mydb.mytbl3;
 
 --echo
 --echo Cleanup 

=== modified file 'sql/backup/be_default.cc'
--- a/sql/backup/be_default.cc	2010-02-24 22:16:05 +0000
+++ b/sql/backup/be_default.cc	2010-03-01 21:31:43 +0000
@@ -549,13 +549,23 @@ result_t Backup::get_data(Buffer &buf)
   case READ_BLOB:
   {
     uint32 size= ((Field_blob*) cur_table->field[*cur_blob])->get_length();
+
+    /*
+      Check to see if blob field is null first. If null, set bit to tell
+      restore to set the field to null.
+    */
+    if (((Field_blob*) cur_table->field[*cur_blob])->is_null())
+      *buf.data= BLOB_NULL;
+    else
+      *buf.data= 0;
+      
     /*
       Check size of buffer to ensure data fits in the buffer. If it does
       not fit, create new blob_buffer object.
     */
     if ((size + META_SIZE) <= buf.size)
     {
-      *buf.data= BLOB_ONCE;
+      *buf.data|= BLOB_ONCE;
       ((Field_blob*) cur_table->field[*cur_blob])->get_ptr((uchar **)&ptr);
       memcpy((byte *)buf.data + META_SIZE, ptr, size);
       buf.size = size + META_SIZE;
@@ -568,7 +578,7 @@ result_t Backup::get_data(Buffer &buf)
 
       ((Field_blob*) cur_table->field[*cur_blob])->get_ptr((uchar **)&ptr);
       blob_buffer.initialize((byte *)ptr, size);
-      *buf.data= BLOB_FIRST;   // First block.
+      *buf.data|= BLOB_FIRST;   // First block.
       uint32 field_size=
         ((Field_blob*) cur_table->field[*cur_blob])->get_length();
       int4store(buf.data + META_SIZE, field_size);     // Save max size.
@@ -797,7 +807,7 @@ result_t Restore::send_data(Buffer &buf)
           hdl->ha_reset_auto_increment(auto_incr);
           break;
         }
-
+        
       // Buffer iterator not needed, just write the data.
       case RCD_ONCE:
       {
@@ -910,7 +920,26 @@ write_skip:
   case WRITE_BLOB:
   {
     uint32 size= buf.size - META_SIZE;
+    bool set_null= (*buf.data & BLOB_NULL);
 
+    // Mask the null status indicator.
+    *buf.data&= BLOB_CTRL;
+    
+    /* 
+      BUG#50357 : Need to check for null fields set at backup time.
+      In this case, we check for null status and set the field accordingly. 
+      If we do not set the field to null, check to see if the length
+      is 0. If it is, then we have a non-null field with a zero length
+      string (e.g. '').
+    */
+    if (*buf.data & (BLOB_ONCE | BLOB_FIRST))
+    {
+      if (set_null)
+        cur_table->field[*cur_blob]->set_null();
+      else if (size == 0)
+        cur_table->field[*cur_blob]->set_notnull();
+    }
+    
     block_type= *buf.data;
     switch (block_type) {
 

=== modified file 'sql/backup/be_default.h'
--- a/sql/backup/be_default.h	2010-02-24 22:16:05 +0000
+++ b/sql/backup/be_default.h	2010-03-01 21:31:43 +0000
@@ -33,7 +33,9 @@ const byte BLOB_ONCE=   3U;     // Singl
 const byte BLOB_FIRST= (3U<<1); // First data block in buffer for blob buffer.
 const byte BLOB_DATA=  (3U<<2); // Intermediate data block for blob buffer.
 const byte BLOB_LAST=  (3U<<3); // Last data block in buffer for blob buffer.
+const byte BLOB_NULL=  (3U<<5); // Stores blob field null status.
 const byte AUTO_INCR=   5U;     // Auto_increment value.
+const byte BLOB_CTRL=  (BLOB_ONCE | BLOB_FIRST | BLOB_DATA | BLOB_LAST);
 
 
 /**


Attachment: [text/bzr-bundle] bzr/charles.bell@sun.com-20100301213143-sxjn187w18si2qrf.bundle
Thread
bzr commit into mysql-6.0-codebase-bugfixing branch(charles.bell:3836) Bug#50357Chuck Bell1 Mar