MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:February 3 2010 5:27pm
Subject:bzr commit into mysql-pe branch (mattias.jonsson:3866) Bug#42438
Bug#49161
View as plain text  
#At file:///Users/mattiasj/clones/bzrroot/topush-mysql-pe/ based on revid:joro@stripped55705-jocelanuayl7it4s

 3866 Mattias Jonsson	2010-02-03 [merge]
      Manual merge of bug#42438 and bug#49161
      from mysql-5.1-bugteam to mysql-pe

    added:
      mysql-test/r/partition_debug_sync.result
      mysql-test/t/partition_debug_sync.test
    modified:
      mysql-test/r/partition_error.result
      mysql-test/t/partition_error.test
      sql/ha_partition.cc
      sql/share/errmsg-utf8.txt
      sql/sql_base.cc
      sql/sql_table.cc
=== added file 'mysql-test/r/partition_debug_sync.result'
--- a/mysql-test/r/partition_debug_sync.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_debug_sync.result	2010-02-03 17:25:31 +0000
@@ -0,0 +1,54 @@
+DROP TABLE IF EXISTS t1, t2;
+SET DEBUG_SYNC= 'RESET';
+#
+# Bug#42438: Crash ha_partition::change_table_ptr
+# Test when remove partitioning is done while drop table is waiting
+# for the table.
+# Con 1
+SET DEBUG_SYNC= 'RESET';
+CREATE TABLE t1
+(a INTEGER,
+b INTEGER NOT NULL,
+KEY (b))
+ENGINE = MYISAM
+/*!50100  PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (2),
+PARTITION p1 VALUES LESS THAN (20),
+PARTITION p2 VALUES LESS THAN (100),
+PARTITION p3 VALUES LESS THAN MAXVALUE ) */;
+SET DEBUG_SYNC= 'alter_table_before_create_temporary_table SIGNAL removing_partitioning WAIT_FOR waiting_for_alter';
+SET DEBUG_SYNC= 'alter_table_before_main_binlog SIGNAL partitioning_removed';
+ALTER TABLE t1 REMOVE PARTITIONING;
+# Con default
+SET DEBUG_SYNC= 'now WAIT_FOR removing_partitioning';
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL waiting_for_alter';
+SET DEBUG_SYNC= 'rm_table_part2_before_delete_table WAIT_FOR partitioning_removed';
+DROP TABLE IF EXISTS t1;
+# Con 1
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC= 'RESET';
+#
+# Bug#42438: Crash ha_partition::change_table_ptr
+# Test when remove partitioning is failing due to drop table is already
+# in progress.
+CREATE TABLE t2
+(a INTEGER,
+b INTEGER NOT NULL,
+KEY (b))
+ENGINE = MYISAM
+/*!50100  PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (2),
+PARTITION p1 VALUES LESS THAN (20),
+PARTITION p2 VALUES LESS THAN (100),
+PARTITION p3 VALUES LESS THAN MAXVALUE ) */;
+SET DEBUG_SYNC= 'before_lock_tables_takes_lock SIGNAL removing_partitions WAIT_FOR waiting_for_alter';
+ALTER TABLE t2 REMOVE PARTITIONING;
+# Con default
+SET DEBUG_SYNC= 'now WAIT_FOR removing_partitions';
+SET DEBUG_SYNC= 'rm_table_part2_before_locking_tables SIGNAL waiting_for_alter';
+DROP TABLE IF EXISTS t2;
+# Con 1
+SET DEBUG_SYNC= 'RESET';
+# Con default
+SET DEBUG_SYNC= 'RESET';
+End of 5.1 tests

=== modified file 'mysql-test/r/partition_error.result'
--- a/mysql-test/r/partition_error.result	2009-12-16 18:16:36 +0000
+++ b/mysql-test/r/partition_error.result	2010-02-03 17:25:31 +0000
@@ -4,6 +4,22 @@ INSERT INTO t1 VALUES (1,2);
 INSERT INTO t1 (a) SELECT * FROM t1;
 ERROR 21S01: Column count doesn't match value count at row 1
 DROP TABLE t1;
+#
+# Bug#49161: Out of memory; restart server and try again (needed 2 bytes)
+#
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a);
+FLUSH TABLES;
+CHECK TABLE t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	Error	Failed to initialize partitions from .par file
+test.t1	check	Error	Incorrect information in file: './test/t1.frm'
+test.t1	check	error	Corrupt
+SELECT * FROM t1;
+ERROR HY000: Failed to initialize partitions from .par file
+# Note that it is currently impossible to drop a partitioned table
+# without the .par file
+DROP TABLE t1;
+ERROR 42S02: Unknown table 't1'
 CREATE TABLE t1 (a INTEGER NOT NULL, PRIMARY KEY (a));
 INSERT INTO t1 VALUES (1),(1);
 ERROR 23000: Duplicate entry '1' for key 'PRIMARY'

=== added file 'mysql-test/t/partition_debug_sync.test'
--- a/mysql-test/t/partition_debug_sync.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_debug_sync.test	2010-02-03 17:25:31 +0000
@@ -0,0 +1,78 @@
+#--disable_abort_on_error
+#
+# Test for the partition storage engine which require DEBUG_SYNC feature to
+# Created by Mattias Jonsson
+#
+--source include/have_partition.inc
+--source include/have_debug_sync.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+SET DEBUG_SYNC= 'RESET';
+--enable_warnings
+
+--echo #
+--echo # Bug#42438: Crash ha_partition::change_table_ptr
+--echo # Test when remove partitioning is done while drop table is waiting
+--echo # for the table.
+connect(con1, localhost, root,,);
+--echo # Con 1
+SET DEBUG_SYNC= 'RESET';
+CREATE TABLE t1
+(a INTEGER,
+ b INTEGER NOT NULL,
+ KEY (b))
+ENGINE = MYISAM
+/*!50100  PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (2),
+ PARTITION p1 VALUES LESS THAN (20),
+ PARTITION p2 VALUES LESS THAN (100),
+ PARTITION p3 VALUES LESS THAN MAXVALUE ) */;
+SET DEBUG_SYNC= 'alter_table_before_create_temporary_table SIGNAL removing_partitioning WAIT_FOR waiting_for_alter';
+SET DEBUG_SYNC= 'alter_table_before_main_binlog SIGNAL partitioning_removed';
+--send ALTER TABLE t1 REMOVE PARTITIONING
+connection default;
+--echo # Con default
+SET DEBUG_SYNC= 'now WAIT_FOR removing_partitioning';
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL waiting_for_alter';
+SET DEBUG_SYNC= 'rm_table_part2_before_delete_table WAIT_FOR partitioning_removed';
+DROP TABLE IF EXISTS t1;
+--echo # Con 1
+connection con1;
+--reap
+connection default;
+SET DEBUG_SYNC= 'RESET';
+connection con1;
+SET DEBUG_SYNC= 'RESET';
+
+--echo #
+--echo # Bug#42438: Crash ha_partition::change_table_ptr
+--echo # Test when remove partitioning is failing due to drop table is already
+--echo # in progress.
+CREATE TABLE t2
+(a INTEGER,
+ b INTEGER NOT NULL,
+ KEY (b))
+ENGINE = MYISAM
+/*!50100  PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (2),
+ PARTITION p1 VALUES LESS THAN (20),
+ PARTITION p2 VALUES LESS THAN (100),
+ PARTITION p3 VALUES LESS THAN MAXVALUE ) */;
+SET DEBUG_SYNC= 'before_lock_tables_takes_lock SIGNAL removing_partitions WAIT_FOR waiting_for_alter';
+--send ALTER TABLE t2 REMOVE PARTITIONING
+connection default;
+--echo # Con default
+SET DEBUG_SYNC= 'now WAIT_FOR removing_partitions';
+SET DEBUG_SYNC= 'rm_table_part2_before_locking_tables SIGNAL waiting_for_alter';
+DROP TABLE IF EXISTS t2;
+--echo # Con 1
+connection con1;
+--reap
+SET DEBUG_SYNC= 'RESET';
+disconnect con1;
+connection default;
+--echo # Con default
+SET DEBUG_SYNC= 'RESET';
+
+--echo End of 5.1 tests

=== modified file 'mysql-test/t/partition_error.test'
--- a/mysql-test/t/partition_error.test	2009-12-16 18:16:36 +0000
+++ b/mysql-test/t/partition_error.test	2010-02-03 17:25:31 +0000
@@ -7,6 +7,7 @@
 --disable_warnings
 drop table if exists t1;
 --enable_warnings
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
 
 #
 # Bug#44108: Assertion bitmap_is_set in ha_partition::end_bulk_insert
@@ -17,7 +18,23 @@ INSERT INTO t1 VALUES (1,2);
 INSERT INTO t1 (a) SELECT * FROM t1;
 DROP TABLE t1;
 
-#
+--echo #
+--echo # Bug#49161: Out of memory; restart server and try again (needed 2 bytes)
+--echo #
+CREATE TABLE t1 (a INT) PARTITION BY HASH (a);
+FLUSH TABLES;
+--remove_file $MYSQLD_DATADIR/test/t1.par
+CHECK TABLE t1;
+--error ER_PAR_FILE_OPEN_ERROR
+SELECT * FROM t1;
+--echo # Note that it is currently impossible to drop a partitioned table
+--echo # without the .par file
+--error ER_BAD_TABLE_ERROR
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.frm
+--remove_file $MYSQLD_DATADIR/test/t1#P#p0.MYI
+--remove_file $MYSQLD_DATADIR/test/t1#P#p0.MYD
+ 
 #
 # Bug#38719: Partitioning returns a different error code for a
 # duplicate key error
@@ -144,7 +161,6 @@ partitions 3
  partition x2 tablespace ts2,
  partition x3 tablespace ts3);
 
-let $MYSQLD_DATADIR= `select @@datadir`;
 select load_file('$MYSQLD_DATADIR/test/t1.par');
 #
 # Partition by hash, invalid field in function

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2010-01-21 08:47:09 +0000
+++ b/sql/ha_partition.cc	2010-02-03 17:25:31 +0000
@@ -355,7 +355,7 @@ bool ha_partition::initialize_partition(
   }
   else if (get_from_handler_file(table_share->normalized_path.str, mem_root))
   {
-    mem_alloc_error(2);
+    my_error(ER_PAR_FILE_OPEN_ERROR, MYF(0));
     DBUG_RETURN(1);
   }
   /*
@@ -1818,13 +1818,23 @@ void ha_partition::update_create_info(HA
 
 void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share)
 {
-  handler **file_array= m_file;
+  handler **file_array;
   table= table_arg;
   table_share= share;
-  do
+  /*
+    m_file can be NULL when using an old cached table in DROP TABLE, when the
+    table just has REMOVED PARTITIONING, see Bug#42438
+  */
+  if (m_file)
   {
-    (*file_array)->change_table_ptr(table_arg, share);
-  } while (*(++file_array));
+    file_array= m_file;
+    DBUG_ASSERT(*file_array);
+    do
+    {
+      (*file_array)->change_table_ptr(table_arg, share);
+    } while (*(++file_array));
+  }
+
   if (m_added_file && m_added_file[0])
   {
     /* if in middle of a drop/rename etc */
@@ -6278,7 +6288,13 @@ void ha_partition::print_error(int error
       thd->lex->sql_command != SQLCOM_TRUNCATE)
     m_part_info->print_no_partition_found(table);
   else
-    m_file[m_last_part]->print_error(error, errflag);
+  {
+    /* In case m_file has not been initialized, like in bug#42438 */
+    if (m_file)
+      m_file[m_last_part]->print_error(error, errflag);
+    else
+      handler::print_error(error, errflag);
+  }
   DBUG_VOID_RETURN;
 }
 
@@ -6288,7 +6304,12 @@ bool ha_partition::get_error_message(int
   DBUG_ENTER("ha_partition::get_error_message");
 
   /* Should probably look for my own errors first */
-  DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf));
+
+  /* In case m_file has not been initialized, like in bug#42438 */
+  if (m_file)
+    DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf));
+  DBUG_RETURN(handler::get_error_message(error, buf));
+
 }
 
 

=== modified file 'sql/share/errmsg-utf8.txt'
--- a/sql/share/errmsg-utf8.txt	2010-01-15 07:30:17 +0000
+++ b/sql/share/errmsg-utf8.txt	2010-02-03 17:25:31 +0000
@@ -6207,6 +6207,10 @@ ER_DEBUG_SYNC_HIT_LIMIT
   eng "debug sync point hit limit reached"
   ger "Debug Sync Point Hit Limit erreicht"
 
+ER_PAR_FILE_OPEN_ERROR
+  eng "Failed to initialize partitions from .par file"
+  swe "Fel vid initialisering av partitionerna från .par-filen"
+
 ER_DUP_SIGNAL_SET 42000
         eng "Duplicate condition information item '%s'"
 

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-02-01 15:57:05 +0000
+++ b/sql/sql_base.cc	2010-02-03 17:25:31 +0000
@@ -2220,6 +2220,7 @@ void wait_for_condition(THD *thd, mysql_
   proc_info=thd->proc_info;
   thd_proc_info(thd, "Waiting for table");
   DBUG_ENTER("wait_for_condition");
+  DEBUG_SYNC(thd, "waiting_for_table");
   if (!thd->killed)
     mysql_cond_wait(cond, mutex);
 

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-01-28 22:02:29 +0000
+++ b/sql/sql_table.cc	2010-02-03 17:25:31 +0000
@@ -25,6 +25,9 @@
 #include "sql_show.h"
 #include "transaction.h"
 #include "keycaches.h"
+#if defined(ENABLED_DEBUG_SYNC)
+#include "debug_sync.h"
+#endif
 
 #ifdef __WIN__
 #include <io.h>
@@ -1897,31 +1900,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
   if (!drop_temporary)
     global_schema_lock_guard.lock();
 
-  /*
-    If we have the table in the definition cache, we don't have to check the
-    .frm file to find if the table is a normal table (not view) and what
-    engine to use.
-  */
-  mysql_mutex_lock(&LOCK_open);
-  for (table= tables; table; table= table->next_local)
-  {
-    TABLE_SHARE *share;
-    table->db_type= NULL;
-    if ((share= get_cached_table_share(table->db, table->table_name)))
-      table->db_type= share->db_type();
-
-    /* Disable drop of enabled log tables */
-    if (share && (share->table_category == TABLE_CATEGORY_LOG) &&
-        check_if_log_table(table->db_length, table->db,
-                           table->table_name_length, table->table_name, 1))
-    {
-      mysql_mutex_unlock(&LOCK_open);
-      my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
-      DBUG_RETURN(1);
-    }
-  }
-  mysql_mutex_unlock(&LOCK_open);
-
+  DEBUG_SYNC(thd, "rm_table_part2_before_locking_tables");
   if (!drop_temporary)
   {
     if (!thd->locked_tables_mode)
@@ -1976,7 +1955,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
   {
     char *db=table->db;
     handlerton *table_type;
-    enum legacy_db_type frm_db_type;
+    enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
 
     DBUG_PRINT("table", ("table_l: '%s'.'%s'  table: %p  s: %p",
                          table->db, table->table_name, table->table,
@@ -2047,7 +2026,6 @@ int mysql_rm_table_part2(THD *thd, TABLE
       built_query.append("`,");
     }
 
-    table_type= table->db_type;
     if (!drop_temporary)
     {
       if (thd->locked_tables_mode)
@@ -2078,9 +2056,19 @@ int mysql_rm_table_part2(THD *thd, TABLE
             Is exclusive meta-data lock enough ?
     */
     mysql_mutex_lock(&LOCK_open);
+
+    /* Disable drop of enabled log tables */
+    if (check_if_log_table(table->db_length, table->db,
+                           table->table_name_length, table->table_name, 1))
+    {
+      my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
+      mysql_mutex_unlock(&LOCK_open);
+      DBUG_RETURN(1);
+    }
+
+    DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
     if (drop_temporary ||
-        ((table_type == NULL &&        
-         access(path, F_OK) &&
+        ((access(path, F_OK) &&
           ha_create_table_from_engine(thd, db, alias)) ||
          (!drop_view &&
           mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
@@ -2096,15 +2084,25 @@ int mysql_rm_table_part2(THD *thd, TABLE
     else
     {
       char *end;
-      if (table_type == NULL)
+      /*
+        Cannot use the db_type from the table, since that might have changed
+        while waiting for the exclusive name lock. We are under LOCK_open,
+        so reading from the frm-file is safe.
+      */
+      if (frm_db_type == DB_TYPE_UNKNOWN)
       {
         mysql_frm_type(thd, path, &frm_db_type);
-        table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
+        DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
       }
+      table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
       // Remove extension for delete
       *(end= path + path_length - reg_ext_length)= '\0';
+      DBUG_PRINT("info", ("deleting table of type %d",
+                          (table_type ? table_type->db_type : 0)));
       error= ha_delete_table(thd, table_type, path, db, table->table_name,
                              !dont_log_query);
+
+      /* No error if non existent table and 'IF EXIST' clause or view */
       if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && 
 	  (if_exists || table_type == NULL))
       {
@@ -2146,6 +2144,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
     DBUG_PRINT("table", ("table: %p  s: %p", table->table,
                          table->table ? table->table->s : (TABLE_SHARE *)-1));
   }
+  DEBUG_SYNC(thd, "rm_table_part2_before_binlog");
   thd->thread_specific_used|= tmp_table_deleted;
   error= 0;
 
@@ -7475,6 +7474,7 @@ view_err:
 
 
   /* Create a temporary table with the new format */
+  DEBUG_SYNC(thd, "alter_table_before_create_temporary_table");
   if ((error= create_temporary_table(thd, table, new_db, tmp_name, 
                                      create_info, alter_info, 
                                      !strcmp(db, new_db))))

Attachment: [text/bzr-bundle]
Thread
bzr commit into mysql-pe branch (mattias.jonsson:3866) Bug#42438Bug#49161Mattias Jonsson3 Feb