List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:July 22 2011 3:54pm
Subject:bzr push into mysql-trunk branch (Dmitry.Lenev:3292 to 3293) Bug#11754210
View as plain text  
 3293 Dmitry Lenev	2011-07-22 [merge]
      Merged fix for bug #11754210 - "45777: CHECK TABLE
      DOESN'T SHOW ALL PROBLEMS FOR MERGE TABLE COMPLIANCE
      IN 5.1" into mysql-trunk.

    modified:
      mysql-test/r/merge.result
      mysql-test/t/merge.test
      sql/sql_base.cc
      storage/myisammrg/ha_myisammrg.cc
      storage/myisammrg/myrg_open.c
 3292 Tor Didriksen	2011-07-22
      Bug#12532830 post-push fix: windows case sensitivity ....

    modified:
      mysql-test/suite/innodb/r/innodb_bug54044.result
      mysql-test/suite/innodb/t/innodb_bug54044.test
=== modified file 'mysql-test/r/merge.result'
--- a/mysql-test/r/merge.result	2011-03-26 10:56:27 +0000
+++ b/mysql-test/r/merge.result	2011-07-22 15:52:42 +0000
@@ -904,7 +904,8 @@ SELECT * FROM tm1;
 ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 CHECK TABLE tm1;
 Table	Op	Msg_type	Msg_text
-test.tm1	check	Error	Table 'test.t1' doesn't exist
+test.tm1	check	Error	Table 'test.t1' is differently defined or of non-MyISAM type or doesn't exist
+test.tm1	check	Error	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	error	Corrupt
 CREATE TABLE t1(a INT);
@@ -912,7 +913,7 @@ SELECT * FROM tm1;
 ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 CHECK TABLE tm1;
 Table	Op	Msg_type	Msg_text
-test.tm1	check	Error	Table 'test.t2' doesn't exist
+test.tm1	check	Error	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	error	Corrupt
 CREATE TABLE t2(a BLOB);
@@ -920,7 +921,7 @@ SELECT * FROM tm1;
 ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 CHECK TABLE tm1;
 Table	Op	Msg_type	Msg_text
-test.tm1	check	Warning	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
+test.tm1	check	Error	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 test.tm1	check	error	Corrupt
 ALTER TABLE t2 MODIFY a INT;
@@ -3635,7 +3636,7 @@ test.t1	analyze	Error	Unable to open und
 test.t1	analyze	error	Corrupt
 CHECK TABLE t1;
 Table	Op	Msg_type	Msg_text
-test.t1	check	Error	Table 'test.t_not_exists' doesn't exist
+test.t1	check	Error	Table 'test.t_not_exists' is differently defined or of non-MyISAM type or doesn't exist
 test.t1	check	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 test.t1	check	error	Corrupt
 CHECKSUM TABLE t1;
@@ -3651,7 +3652,7 @@ test.t1	optimize	Error	Unable to open un
 test.t1	optimize	error	Corrupt
 REPAIR TABLE t1;
 Table	Op	Msg_type	Msg_text
-test.t1	repair	Error	Table 'test.t_not_exists' doesn't exist
+test.t1	repair	Error	Table 'test.t_not_exists' is differently defined or of non-MyISAM type or doesn't exist
 test.t1	repair	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 test.t1	repair	error	Corrupt
 REPAIR TABLE t1 USE_FRM;
@@ -3678,6 +3679,40 @@ ERROR HY000: Table 't1' was locked with 
 UNLOCK TABLES;
 DROP TABLE m1, t1;
 #
+# Test for bug #11754210 - "45777: CHECK TABLE DOESN'T SHOW ALL
+#                           PROBLEMS FOR MERGE TABLE COMPLIANCE IN 5.1"
+#
+drop tables if exists t1, t2, t3, t4, m1;
+create table t1(id int) engine=myisam;
+create view t3 as select 1 as id;
+create table t4(id int) engine=memory;
+create table m1(id int) engine=merge union=(t1,t2,t3,t4);
+select * from m1;
+ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+# The below CHECK and REPAIR TABLE statements should
+# report all problems with underlying tables: 
+# - absence of 't2',
+# - missing base table for 't3',
+# - wrong engine of 't4'.
+check table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	check	Error	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	check	Error	Table 'test.t3' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	check	Error	Table 'test.t4' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	check	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+test.m1	check	error	Corrupt
+repair table m1;
+Table	Op	Msg_type	Msg_text
+test.m1	repair	Error	Table 'test.t2' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	repair	Error	Table 'test.t3' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	repair	Error	Table 'test.t4' is differently defined or of non-MyISAM type or doesn't exist
+test.m1	repair	Error	Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+test.m1	repair	error	Corrupt
+# Clean-up.
+drop tables m1, t1, t4;
+drop view t3;
+End of 5.5 tests
+#
 # Additional coverage for refactoring which is made as part
 # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
 # to allow temp table operations".
@@ -3766,4 +3801,3 @@ ERROR HY000: Unable to open underlying t
 DROP TRIGGER trg1;
 DROP TABLE t1;
 DROP TABLE m1;
-End of 6.0 tests

=== modified file 'mysql-test/t/merge.test'
--- a/mysql-test/t/merge.test	2011-03-26 10:56:27 +0000
+++ b/mysql-test/t/merge.test	2011-07-22 15:52:42 +0000
@@ -2800,6 +2800,34 @@ DROP TABLE m1, t1;
 
 
 --echo #
+--echo # Test for bug #11754210 - "45777: CHECK TABLE DOESN'T SHOW ALL
+--echo #                           PROBLEMS FOR MERGE TABLE COMPLIANCE IN 5.1"
+--echo #
+--disable_warnings
+drop tables if exists t1, t2, t3, t4, m1;
+--enable_warnings
+create table t1(id int) engine=myisam;
+create view t3 as select 1 as id;
+create table t4(id int) engine=memory;
+create table m1(id int) engine=merge union=(t1,t2,t3,t4);
+--error ER_WRONG_MRG_TABLE
+select * from m1;
+--echo # The below CHECK and REPAIR TABLE statements should
+--echo # report all problems with underlying tables: 
+--echo # - absence of 't2',
+--echo # - missing base table for 't3',
+--echo # - wrong engine of 't4'.
+check table m1;
+repair table m1;
+--echo # Clean-up.
+drop tables m1, t1, t4;
+drop view t3;
+
+
+--echo End of 5.5 tests
+
+
+--echo #
 --echo # Additional coverage for refactoring which is made as part
 --echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
 --echo # to allow temp table operations".
@@ -2877,7 +2905,6 @@ DROP TRIGGER trg1;
 DROP TABLE t1;
 DROP TABLE m1;
 
---echo End of 6.0 tests
 
 --disable_result_log
 --disable_query_log

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2011-07-20 14:40:52 +0000
+++ b/sql/sql_base.cc	2011-07-22 15:52:42 +0000
@@ -88,6 +88,69 @@ bool No_such_table_error_handler::safely
   return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
 }
 
+
+/**
+  This internal handler is used to trap ER_NO_SUCH_TABLE and
+  ER_WRONG_MRG_TABLE errors during CHECK/REPAIR TABLE for MERGE
+  tables.
+*/
+
+class Repair_mrg_table_error_handler : public Internal_error_handler
+{
+public:
+  Repair_mrg_table_error_handler()
+    : m_handled_errors(false), m_unhandled_errors(false)
+  {}
+
+  bool handle_condition(THD *thd,
+                        uint sql_errno,
+                        const char* sqlstate,
+                        MYSQL_ERROR::enum_warning_level level,
+                        const char* msg,
+                        MYSQL_ERROR ** cond_hdl);
+
+  /**
+    Returns TRUE if there were ER_NO_SUCH_/WRONG_MRG_TABLE and there
+    were no unhandled errors. FALSE otherwise.
+  */
+  bool safely_trapped_errors()
+  {
+    /*
+      Check for m_handled_errors is here for extra safety.
+      It can be useful in situation when call to open_table()
+      fails because some error which was suppressed by another
+      error handler (e.g. in case of MDL deadlock which we
+      decided to solve by back-off and retry).
+    */
+    return (m_handled_errors && (! m_unhandled_errors));
+  }
+
+private:
+  bool m_handled_errors;
+  bool m_unhandled_errors;
+};
+
+
+bool
+Repair_mrg_table_error_handler::handle_condition(THD *,
+                                                 uint sql_errno,
+                                                 const char*,
+                                                 MYSQL_ERROR::enum_warning_level level,
+                                                 const char*,
+                                                 MYSQL_ERROR ** cond_hdl)
+{
+  *cond_hdl= NULL;
+  if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_WRONG_MRG_TABLE)
+  {
+    m_handled_errors= true;
+    return TRUE;
+  }
+
+  m_unhandled_errors= true;
+  return FALSE;
+}
+
+
 /**
   @defgroup Data_Dictionary Data Dictionary
   @{
@@ -4430,6 +4493,24 @@ open_and_process_table(THD *thd, LEX *le
     thd->pop_internal_handler();
     safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
   }
+  else if (tables->parent_l && (thd->open_options & HA_OPEN_FOR_REPAIR))
+  {
+    /*
+      Also fail silently for underlying tables of a MERGE table if this
+      table is opened for CHECK/REPAIR TABLE statement. This is needed
+      to provide complete list of problematic underlying tables in
+      CHECK/REPAIR TABLE output.
+    */
+    Repair_mrg_table_error_handler repair_mrg_table_handler;
+    thd->push_internal_handler(&repair_mrg_table_handler);
+
+    error= open_temporary_table(thd, tables);
+    if (!error && !tables->table)
+      error= open_table(thd, tables, new_frm_mem, ot_ctx);
+
+    thd->pop_internal_handler();
+    safe_to_ignore_table= repair_mrg_table_handler.safely_trapped_errors();
+  }
   else
   {
     if (tables->parent_l)

=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc	2011-07-04 00:25:46 +0000
+++ b/storage/myisammrg/ha_myisammrg.cc	2011-07-22 15:52:42 +0000
@@ -155,9 +155,14 @@ extern "C" void myrg_print_wrong_table(c
   buf[db.length]= '.';
   memcpy(buf + db.length + 1, name.str, name.length);
   buf[db.length + name.length + 1]= 0;
-  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                      ER_ADMIN_WRONG_MRG_TABLE, ER(ER_ADMIN_WRONG_MRG_TABLE),
-                      buf);
+  /*
+    Push an error to be reported as part of CHECK/REPAIR result-set.
+    Note that calling my_error() from handler is a hack which is kept
+    here to avoid refactoring. Normally engines should report errors
+    through return value which will be interpreted by caller using
+    handler::print_error() call.
+  */
+  my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), buf);
 }
 
 
@@ -594,8 +599,7 @@ public:
 
   @return       pointer to open MyISAM table structure
     @retval     !=NULL                  OK, returning pointer
-    @retval     NULL, my_errno == 0     Ok, no more child tables
-    @retval     NULL, my_errno != 0     error
+    @retval     NULL,                   Error.
 
   @detail
     This function retrieves the MyISAM table handle from the
@@ -615,22 +619,23 @@ extern "C" MI_INFO *myisammrg_attach_chi
   MI_INFO       *myisam= NULL;
   DBUG_ENTER("myisammrg_attach_children_callback");
 
-  if (!child_l)
-  {
-    DBUG_PRINT("myrg", ("No more children to attach"));
-    my_errno= 0; /* Ok, no more child tables. */
-    goto end;
-  }
+  /*
+    Number of children in the list and MYRG_INFO::tables_count,
+    which is used by caller of this function, should always match.
+  */
+  DBUG_ASSERT(child_l);
+
   child= child_l->table;
 
+  /* Prepare for next child. */
+  param->next();
+
   if (!child)
   {
-    DBUG_PRINT("myrg", ("Child table does not exist"));
-    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
+    DBUG_PRINT("error", ("failed to open underlying table '%s'.'%s'",
+                         child_l->db, child_l->table_name));
     goto end;
   }
-  /* Prepare for next child. */
-  param->next();
 
   /*
     Do a quick compatibility check. The table def version is set when
@@ -661,7 +666,6 @@ extern "C" MI_INFO *myisammrg_attach_chi
   {
     DBUG_PRINT("error", ("temporary table mismatch parent: %d  child: %d",
                          parent->s->tmp_table, child->s->tmp_table));
-    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
     goto end;
   }
 
@@ -672,12 +676,27 @@ extern "C" MI_INFO *myisammrg_attach_chi
     DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' 0x%lx",
                          child->s->db.str, child->s->table_name.str,
                          (long) child));
-    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
   }
-  DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx  my_errno: %d",
-                      my_errno ? 0L : (long) myisam, my_errno));
+
+  DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx", (long) myisam));
 
  end:
+
+  if (!myisam &&
+      (current_thd->open_options & HA_OPEN_FOR_REPAIR))
+  {
+    char buf[2*NAME_LEN + 1 + 1];
+    strxnmov(buf, sizeof(buf) - 1, child_l->db, ".", child_l->table_name, NULL);
+    /*
+      Push an error to be reported as part of CHECK/REPAIR result-set.
+      Note that calling my_error() from handler is a hack which is kept
+      here to avoid refactoring. Normally engines should report errors
+      through return value which will be interpreted by caller using
+      handler::print_error() call.
+    */
+    my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), buf);
+  }
+
   DBUG_RETURN(myisam);
 }
 
@@ -791,12 +810,6 @@ int ha_myisammrg::attach_children(void)
   /* Must call this with children list in place. */
   DBUG_ASSERT(this->table->pos_in_table_list->next_global == this->children_l);
 
-  /*
-    'my_errno' is set by myisammrg_attach_children_callback() in
-    case of an error.
-  */
-  my_errno= 0;
-
   if (myrg_attach_children(this->file, this->test_if_locked |
                            current_thd->open_options,
                            myisammrg_attach_children_callback, &param,

=== modified file 'storage/myisammrg/myrg_open.c'
--- a/storage/myisammrg/myrg_open.c	2011-06-30 15:50:45 +0000
+++ b/storage/myisammrg/myrg_open.c	2011-07-22 15:52:42 +0000
@@ -385,6 +385,7 @@ int myrg_attach_children(MYRG_INFO *m_in
   uint       UNINIT_VAR(key_parts);
   uint       min_keys;
   my_bool    bad_children= FALSE;
+  my_bool    first_child= TRUE;
   DBUG_ENTER("myrg_attach_children");
   DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking));
 
@@ -399,16 +400,26 @@ int myrg_attach_children(MYRG_INFO *m_in
   errpos= 0;
   file_offset= 0;
   min_keys= 0;
-  child_nr= 0;
-  while ((myisam= (*callback)(callback_param)))
+  for (child_nr= 0; child_nr < m_info->tables; child_nr++)
   {
+    if (! (myisam= (*callback)(callback_param)))
+    {
+      if (handle_locking & HA_OPEN_FOR_REPAIR)
+      {
+        /* An appropriate error should've been already pushed by callback. */
+        bad_children= TRUE;
+        continue;
+      }
+      goto bad_children;
+    }
+
     DBUG_PRINT("myrg", ("child_nr: %u  table: '%s'",
                         child_nr, myisam->filename));
-    DBUG_ASSERT(child_nr < m_info->tables);
 
     /* Special handling when the first child is attached. */
-    if (!child_nr)
+    if (first_child)
     {
+      first_child= FALSE;
       m_info->reclength= myisam->s->base.reclength;
       min_keys=  myisam->s->base.keys;
       key_parts= myisam->s->base.key_parts;
@@ -456,14 +467,11 @@ int myrg_attach_children(MYRG_INFO *m_in
     for (idx= 0; idx < key_parts; idx++)
       m_info->rec_per_key_part[idx]+= (myisam->s->state.rec_per_key_part[idx] /
                                        m_info->tables);
-    child_nr++;
   }
 
   if (bad_children)
     goto bad_children;
-  /* Note: callback() resets my_errno, so it is safe to check it here */
-  if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
-    goto err;
+
   if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
   {
     my_errno= HA_ERR_RECORD_FILE_FULL;

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (Dmitry.Lenev:3292 to 3293) Bug#11754210Dmitry Lenev22 Jul