List:Commits« Previous MessageNext Message »
From:He Zhenxing Date:July 24 2008 5:09am
Subject:bzr commit into mysql-5.1 branch (hezx:2630) Bug#37051
View as plain text  
#At file:///media/sda3/work/mysql/bzrwork/b37051/5.1-rpl/

 2630 He Zhenxing	2008-07-24
      BUG#37051 Replication rules not evaluated correctly
      
      Replication filter rules are applied on the tables list for update, 
      however, in order to get the list of update tables, all tables need
      to be opened to resolve update fields, which would result in a failure
      if some of the tables involved in the multi-update statement are not
      exist on slave.
      
      This patch fixes this problem by ignoring tables not exist on slave
      and continue the process of resolving fields with the tables exist
      and apply the filter rules upon the tables exist on slave and will be
      updated by the multi-update statement.
modified:
  sql/item.cc
  sql/mysql_priv.h
  sql/sql_base.cc
  sql/sql_update.cc

per-file messages:
  sql/item.cc
    if field is not resolve, return 0 as the table map
  sql/mysql_priv.h
    add ignore_non_exist argument to setup_tables and setup_fields functions
  sql/sql_base.cc
    add ignore_non_exist parameter to open_tables to ignore non exist tables
  sql/sql_update.cc
    call open_tables, setup_tables and setup_fields with ignore_non_exist parameter if running in slave thread
    ignore non-exist tables
=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-05-20 07:38:17 +0000
+++ b/sql/item.cc	2008-07-24 05:09:37 +0000
@@ -2113,6 +2113,8 @@ bool Item_field::eq(const Item *item, bo
 
 table_map Item_field::used_tables() const
 {
+  if (!field)
+    return 0;
   if (field->table->const_table)
     return 0;					// const item
   return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map);

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-05-20 07:29:16 +0000
+++ b/sql/mysql_priv.h	2008-07-24 05:09:37 +0000
@@ -1482,7 +1482,8 @@ bool insert_fields(THD *thd, Name_resolu
                    List_iterator<Item> *it, bool any_privileges);
 bool setup_tables(THD *thd, Name_resolution_context *context,
                   List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
-                  TABLE_LIST **leaves, bool select_insert);
+                  TABLE_LIST **leaves, bool select_insert,
+                  bool ignore_non_exist=FALSE);
 bool setup_tables_and_check_access(THD *thd, 
                                    Name_resolution_context *context,
                                    List<TABLE_LIST> *from_clause, 
@@ -1490,22 +1491,25 @@ bool setup_tables_and_check_access(THD *
                                    TABLE_LIST **leaves, 
                                    bool select_insert,
                                    ulong want_access_first,
-                                   ulong want_access);
+                                   ulong want_access,
+                                   bool ignore_non_exist=FALSE);
 int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
 	       List<Item> *sum_func_list, uint wild_num);
 bool setup_fields(THD *thd, Item** ref_pointer_array,
                   List<Item> &item, enum_mark_columns mark_used_columns,
-                  List<Item> *sum_func_list, bool allow_sum_func);
+                  List<Item> *sum_func_list, bool allow_sum_func,
+                  bool ignore_non_exist=FALSE);
 inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
                                       List<Item> &item,
                                       enum_mark_columns mark_used_columns,
                                       List<Item> *sum_func_list,
-                                      bool allow_sum_func)
+                                      bool allow_sum_func,
+                                      bool ignore_non_exist=FALSE)
 {
   bool res;
   thd->lex->select_lex.no_wrap_view_item= TRUE;
   res= setup_fields(thd, ref_pointer_array, item, mark_used_columns, sum_func_list,
-                    allow_sum_func);
+                    allow_sum_func, ignore_non_exist);
   thd->lex->select_lex.no_wrap_view_item= FALSE;
   return res;
 }
@@ -1515,7 +1519,8 @@ int setup_ftfuncs(SELECT_LEX* select);
 int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
 void wait_for_condition(THD *thd, pthread_mutex_t *mutex,
                         pthread_cond_t *cond);
-int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags);
+int open_tables(THD *thd, TABLE_LIST **tables,
+                uint *counter, uint flags, bool *ignore_non_exist=0);
 /* open_and_lock_tables with optional derived handling */
 int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived);
 /* simple open_and_lock_tables without derived handling */

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-05-20 07:38:17 +0000
+++ b/sql/sql_base.cc	2008-07-24 05:09:37 +0000
@@ -4386,7 +4386,8 @@ bool fix_merge_after_open(TABLE_LIST *ol
     -1 - error
 */
 
-int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
+int open_tables(THD *thd, TABLE_LIST **start,
+                uint *counter, uint flags, bool *ignore_non_exist)
 {
   TABLE_LIST *tables= NULL;
   bool refresh;
@@ -4582,6 +4583,12 @@ int open_tables(THD *thd, TABLE_LIST **s
 	goto restart;
       }
 
+      if (ignore_non_exist)
+      {
+        *ignore_non_exist= TRUE;
+        continue;
+      }
+      
       if (safe_to_ignore_table)
       {
         DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
@@ -5840,7 +5847,7 @@ find_field_in_table_ref(THD *thd, TABLE_
                         uint *cached_field_index_ptr,
                         bool register_tree_change, TABLE_LIST **actual_table)
 {
-  Field *fld;
+  Field *fld= 0;
   DBUG_ENTER("find_field_in_table_ref");
   DBUG_ASSERT(table_list->alias);
   DBUG_ASSERT(name);
@@ -5891,6 +5898,9 @@ find_field_in_table_ref(THD *thd, TABLE_
   }
   else if (!table_list->nested_join)
   {
+    if (!table_list->table)
+      DBUG_RETURN(NULL);
+
     /* 'table_list' is a stored table. */
     DBUG_ASSERT(table_list->table);
     if ((fld= find_field_in_table(thd, table_list->table, name, length,
@@ -7263,7 +7273,8 @@ int setup_wild(THD *thd, TABLE_LIST *tab
 
 bool setup_fields(THD *thd, Item **ref_pointer_array,
                   List<Item> &fields, enum_mark_columns mark_used_columns,
-                  List<Item> *sum_func_list, bool allow_sum_func)
+                  List<Item> *sum_func_list, bool allow_sum_func,
+                  bool ignore_non_exist)
 {
   reg2 Item *item;
   enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
@@ -7301,6 +7312,8 @@ bool setup_fields(THD *thd, Item **ref_p
     if (!item->fixed && item->fix_fields(thd, it.ref()) ||
 	(item= *(it.ref()))->check_cols(1))
     {
+      if (ignore_non_exist)
+        continue;
       thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
       thd->lex->allow_sum_func= save_allow_sum_func;
       thd->mark_used_columns= save_mark_used_columns;
@@ -7385,7 +7398,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST
 
 bool setup_tables(THD *thd, Name_resolution_context *context,
                   List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
-                  TABLE_LIST **leaves, bool select_insert)
+                  TABLE_LIST **leaves, bool select_insert, bool ignore_non_exist)
 {
   uint tablenr= 0;
   DBUG_ENTER("setup_tables");
@@ -7407,6 +7420,8 @@ bool setup_tables(THD *thd, Name_resolut
        table_list;
        table_list= table_list->next_leaf, tablenr++)
   {
+    if (ignore_non_exist && !table_list->table)
+      continue;
     TABLE *table= table_list->table;
     table->pos_in_table_list= table_list;
     if (first_select_table &&
@@ -7447,6 +7462,9 @@ bool setup_tables(THD *thd, Name_resolut
     }
   }
 
+  if (ignore_non_exist)
+    DBUG_RETURN(0);
+  
   /* Precompute and store the row types of NATURAL/USING joins. */
   if (setup_natural_join_row_types(thd, from_clause, context))
     DBUG_RETURN(1);
@@ -7485,13 +7503,14 @@ bool setup_tables_and_check_access(THD *
                                    TABLE_LIST **leaves,
                                    bool select_insert,
                                    ulong want_access_first,
-                                   ulong want_access)
+                                   ulong want_access,
+                                   bool ignore_non_exist)
 {
   TABLE_LIST *leaves_tmp= NULL;
   bool first_table= true;
 
   if (setup_tables(thd, context, from_clause, tables,
-                   &leaves_tmp, select_insert))
+                   &leaves_tmp, select_insert, ignore_non_exist))
     return TRUE;
 
   if (leaves)

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2008-05-20 07:38:17 +0000
+++ b/sql/sql_update.cc	2008-07-24 05:09:37 +0000
@@ -965,11 +965,27 @@ int mysql_multi_update_prepare(THD *thd)
 
 reopen_tables:
 
+  /* BUG#37051 if we are in the slave SQL thread, it is possible that
+     some tables use by a multi-update statement are not exist on the
+     slave. But we cannot let the statement fail with such an error
+     because in some cases this statement will be filtered out by the
+     replication do or ignore rules. So we open all the tables that
+     are exist and try to resolve the fields with these existing
+     tables and figure out which tables are to be updated. that we can
+     later run 'all_tables_not_ok' to check if this statement should
+     be ignored or not.
+  */
+  bool ignore_non_exist= FALSE;
+  bool *ignore_ptr= 0;
+  if (thd->slave_thread)
+    ignore_ptr= &ignore_non_exist;
+  
   /* open tables and create derived ones, but do not lock and fill them */
   if (((original_multiupdate || need_reopen) &&
-       open_tables(thd, &table_list, &table_count, 0)) ||
+       open_tables(thd, &table_list, &table_count, 0, ignore_ptr)) ||
       mysql_handle_derived(lex, &mysql_derived_prepare))
     DBUG_RETURN(TRUE);
+
   /*
     setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
     second time, but this call will do nothing (there are check for second
@@ -980,10 +996,12 @@ reopen_tables:
                                     &lex->select_lex.top_join_list,
                                     table_list,
                                     &lex->select_lex.leaf_tables, FALSE,
-                                    UPDATE_ACL, SELECT_ACL))
+                                    UPDATE_ACL, SELECT_ACL, ignore_non_exist))
     DBUG_RETURN(TRUE);
 
-  if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
+  if (ignore_non_exist)
+    setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0, TRUE);
+  else if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
     DBUG_RETURN(TRUE);
 
   for (tl= table_list; tl ; tl= tl->next_local)
@@ -1009,6 +1027,13 @@ reopen_tables:
   for (tl= leaves; tl; tl= tl->next_leaf)
   {
     TABLE *table= tl->table;
+    if (!table)
+    {
+      /* table does not exist on slave, assume it not updating */
+      tl->updating= FALSE;
+      continue;
+    }
+
     /* Only set timestamp column if this is not modified */
     if (table->timestamp_field &&
         bitmap_is_set(table->write_set,
@@ -1046,8 +1071,14 @@ reopen_tables:
         tl->table->reginfo.lock_type= tl->lock_type;
     }
   }
+  
+  if (ignore_non_exist)
+    DBUG_RETURN(TRUE);
+  
   for (tl= table_list; tl; tl= tl->next_local)
   {
+    if (!tl->table)
+      continue;
     /* Check access privileges for table */
     if (!tl->derived)
     {
@@ -1063,6 +1094,8 @@ reopen_tables:
   /* check single table update for view compound from several tables */
   for (tl= table_list; tl; tl= tl->next_local)
   {
+    if (!tl->table)
+      continue;
     if (tl->effective_algorithm == VIEW_ALGORITHM_MERGE)
     {
       TABLE_LIST *for_update= 0;

Thread
bzr commit into mysql-5.1 branch (hezx:2630) Bug#37051He Zhenxing24 Jul