List:Commits« Previous MessageNext Message »
From:Praveenkumar Hulakund Date:January 27 2012 8:20am
Subject:bzr push into mysql-trunk branch (praveenkumar.hulakund:3795 to 3796)
Bug#11764786
View as plain text  
 3796 Praveenkumar Hulakund	2012-01-27
      BUG#11764786: 57657: TEMPORARY MERGE TABLE WITH TEMPORARY UNDERLYING IS BROKEN BY ALTER
            
            Analysis:
            --------------------------------------------
            When merge table is created, then MyISAM MERGE creates a file .MRG. Engine adds
            names of the tables (children tables) and insert method in this file. So, if we
            consider the tables listed in "HOW TO REPEAT" section then content of .MRG file 
            of "tm_temp_temp"table  will be as below
            
                    >cat #<tmp_file_name>.MRG
                    -----------------------
                    ./test/t1_temp
                    #INSERT_METHOD=FIRST
                    -----------------------
            
            So for both, temporary and non-temporary children table "table name" is added in
            .MRG file in "./<db_name>/<table_name>" format. So that the table can be opened
            using <db_name>.<table_name> [from comments written in function 
            "ha_myisammrg::create"].
            
            When sql query to alter merge table "tm_temp_temp" is called then "mysql_alter_table"
            function calls "open_and_lock_tables" which in turn call the table open function of 
            MyISAM MERGE storage. MyISAM MERGE storage handler, holds all the open table 
            information in open_tables of type MYRG_TABLE.So, in open function of MyISAM Merge 
            handler, table "tm_temp_temp" is opened and held with the open_tables.
            
            Since, this merge table contains child_table (t1_temp). All the child table are 
            opened and TABLE_LIST of child table will be "children_l" member of MyISAM Merge handler.
            children_l is doubly linked list of all child tables.
            
                children_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
                #             #               ^          #               ^
                #             #               |          #               |
                #             #               +--------- TABLE_LIST::prev_global
                #             #                                          |
                #       |<--- TABLE_LIST::prev_global                    |
                #                                                        |
                children_last_l -----------------------------------------+
            
            
            And information of all child tables are also held in the open_tables of MyISAM merge 
            handler.
            
            The name of the table file for each table opened is held in the "filename" of 
            open_tables->table (type is struct st_myisam_info). 
            
            * Why merge table is getting corrupted in "alter table"?
              Alter table calls function "update_create_info" function. In "update_create_info"
              function of MyISAM Merge Handler, merge list (TABLE_LIST of child tables) is 
              populated in create_info object of type HA_CREATE_INFO. And this list is then used 
              to create new .MRG file to reflect the alter operations.
            
              In function, "update_create_info" of MyISAM MERGE, the DB name and the TABLE name
              are extracted from the filename stored in the member "open_tables->table->filename"
              as below,
            
                split_file_name(open_table->table->filename, &db_name, &file_name);
            
              This db name and file name are stored in the create_info object. And while creating
              the .MRG file, table name of the child table is written into it in the 
              "./<db_name>/<table_name> format.
            
              When merge table has non-temporary child tables then "filename" contains proper db 
              name and file name.
            
              But when merge table has temporary tables then "filename" has a temporary filename
              created in "/tmp" directory (for eg: /tmp/#sql7a3b_2_1). So when "split_file_name"
              function is called with this value, "tmp" is stored in the db name "#sql7a3b_2_1"
              is stored in the file name. So here while creating new .MRG file, "./tmp/#sql7a3b_2_1"
              written as a child entry. 
            
                    >cat #<tmp_file_name>.MRG
                    -----------------------
                    "./tmp/#sql7a3b_2_1"
                    #INSERT_METHOD=LAST
                    -----------------------
            
              After this, any operation on merge table gives error as its fails to find "tmp" DB 
              and table name "#sql7a3b_2_1". And because of the same reason "check table" also
              reported the "table corruption" error.
            
            *. Why we wont see this issue while creating merge table?
               While creating merge table, "create_info" object of type HA_CREATE_INFO is formed by 
               parser with valid "merge_list" (with proper DB name and table name for temporary
               and non-temporary tables). So, create table function of MyISAM MERGE creates .MRG file.
               So, .MRG contains proper entry for table after creating a table.
            
                    >cat #<tmp_file_name>.MRG
                    -----------------------
                    ./test/t1_temp
                    #INSERT_METHOD=FIRST
                    -----------------------
            
               Since, create_info populated with merge_list by parser itself, function "update_create_info"
               is not called.
            
            Possible Fix:
            --------------------------------------------
            Instead of getting db name and table name from "open_tables->table->filename" in 
            update_create_info function, the db name and table name can be obtained from
            the TABLE_LIST of each child table stored in the "children_l" of MyISAM MERGE
            handler. For both the temporary and non-temporary child table the TABLE_LIST 
            is propogated with proper DB name and table name in members "db" and "table_name".
            
            So as a, logic of the "update_create_info" MyISAM MERGE handler is
            changed so that it gets db name and table from TABLE_LIST stored in "children_l".

    modified:
      mysql-test/r/merge.result
      mysql-test/t/merge.test
      storage/myisammrg/ha_myisammrg.cc
 3795 Dmitry Shulga	2012-01-27
      Patch for bug#12872824 (formerly known as 62125): testing stored function
      result for null incorrectly yields 1292 warning.
      
      The reason for this bug was that when server executed expression 'IS NULL'
      for return value of some stored function it calculated the return
      value before checking it for NULL. During return value calculation
      it's assumed that a value has INTEGER type that is not true in general.
      
      The solution is to evaluate return value for NULL without its calculation.
     @ mysql-test/r/sp.result
        Added results of test for bug#12872824.
     @ mysql-test/t/sp.test
        Added test for bug#12872824.
     @ sql/item_func.cc
        Added implementation for virtual method update_null_value into
        Item_func_sp. Implementation for this method doesn't call 
        Item::update_null_value() in order to get null flag for
        return value. Instead we call private method execute() that
        check return value for null and set null flag.

    modified:
      mysql-test/r/sp.result
      mysql-test/t/sp.test
      sql/item_func.cc
      sql/item_func.h
=== modified file 'mysql-test/r/merge.result'
--- a/mysql-test/r/merge.result	revid:dmitry.shulga@stripped
+++ b/mysql-test/r/merge.result	revid:praveenkumar.hulakund@stripped
@@ -3801,3 +3801,23 @@ ERROR HY000: Unable to open underlying t
 DROP TRIGGER trg1;
 DROP TABLE t1;
 DROP TABLE m1;
+#
+# Test for bug #11764786 - 57657: TEMPORARY MERGE TABLE WITH TEMPORARY
+#                                 UNDERLYING TABLE, IS BROKEN BY ALTER.
+#
+DROP TABLES IF EXISTS t1, t2, t3, t4;
+CREATE TEMPORARY TABLE t1(i INT) ENGINE= MyISAM;
+CREATE TEMPORARY TABLE t2(i INT) ENGINE= MERGE UNION= (t1) INSERT_METHOD= LAST;
+ALTER TABLE t2 INSERT_METHOD= FIRST;
+CHECK TABLE t2;
+Table	Op	Msg_type	Msg_text
+test.t2	check	status	OK
+CREATE TABLE t3(i INT) ENGINE= MyISAM;
+CREATE TABLE t4(i int) ENGINE= MERGE UNION= (t3) INSERT_METHOD= LAST;
+ALTER TABLE t4 INSERT_METHOD= FIRST;
+CHECK TABLE t4;
+Table	Op	Msg_type	Msg_text
+test.t4	check	status	OK
+# Clean-up
+DROP TABLES t1, t2, t3, t4;
+# End of bug #11764786 - 57657

=== modified file 'mysql-test/t/merge.test'
--- a/mysql-test/t/merge.test	revid:dmitry.shulga@stripped
+++ b/mysql-test/t/merge.test	revid:praveenkumar.hulakund@stripped
@@ -2905,6 +2905,25 @@ DROP TRIGGER trg1;
 DROP TABLE t1;
 DROP TABLE m1;
 
+--echo #
+--echo # Test for bug #11764786 - 57657: TEMPORARY MERGE TABLE WITH TEMPORARY
+--echo #                                 UNDERLYING TABLE, IS BROKEN BY ALTER.
+--echo #
+--disable_warnings
+DROP TABLES IF EXISTS t1, t2, t3, t4;
+--enable_warnings
+CREATE TEMPORARY TABLE t1(i INT) ENGINE= MyISAM;
+CREATE TEMPORARY TABLE t2(i INT) ENGINE= MERGE UNION= (t1) INSERT_METHOD= LAST;
+ALTER TABLE t2 INSERT_METHOD= FIRST;
+CHECK TABLE t2;
+
+CREATE TABLE t3(i INT) ENGINE= MyISAM;
+CREATE TABLE t4(i int) ENGINE= MERGE UNION= (t3) INSERT_METHOD= LAST;
+ALTER TABLE t4 INSERT_METHOD= FIRST;
+CHECK TABLE t4;
+--echo # Clean-up
+DROP TABLES t1, t2, t3, t4;
+--echo # End of bug #11764786 - 57657
 
 --disable_result_log
 --disable_query_log

=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc	revid:dmitry.shulga@stripped
+++ b/storage/myisammrg/ha_myisammrg.cc	revid:praveenkumar.hulakund@stripped
@@ -1469,31 +1469,36 @@ void ha_myisammrg::update_create_info(HA
 
   if (!(create_info->used_fields & HA_CREATE_USED_UNION))
   {
-    MYRG_TABLE *open_table;
+    TABLE_LIST *child_table;
     THD *thd=current_thd;
 
     create_info->merge_list.next= &create_info->merge_list.first;
     create_info->merge_list.elements=0;
 
-    for (open_table=file->open_tables ;
-	 open_table != file->end_table ;
-	 open_table++)
+    if (children_l != NULL)
     {
-      TABLE_LIST *ptr;
-      LEX_STRING db, name;
-      LINT_INIT(db.str);
-
-      if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
-	goto err;
-      split_file_name(open_table->table->filename, &db, &name);
-      if (!(ptr->table_name= thd->strmake(name.str, name.length)))
-	goto err;
-      if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
-	goto err;
-
-      create_info->merge_list.elements++;
-      (*create_info->merge_list.next) = ptr;
-      create_info->merge_list.next= &ptr->next_local;
+      for (child_table= children_l;;
+           child_table= child_table->next_global)
+      {
+        TABLE_LIST *ptr;
+
+        if (!(ptr= (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
+          goto err;
+
+        if (!(ptr->table_name= thd->strmake(child_table->table_name,
+                                            child_table->table_name_length)))
+          goto err;
+        if (child_table->db && !(ptr->db= thd->strmake(child_table->db,
+                                   child_table->db_length)))
+          goto err;
+
+        create_info->merge_list.elements++;
+        (*create_info->merge_list.next)= ptr;
+        create_info->merge_list.next= &ptr->next_local;
+
+        if (&child_table->next_global == children_last_l)
+          break;
+      }
     }
     *create_info->merge_list.next=0;
   }

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (praveenkumar.hulakund:3795 to 3796)Bug#11764786Praveenkumar Hulakund30 Jan