List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:December 1 2009 3:24pm
Subject:bzr push into mysql-5.6-next-mr branch (kostja:2962 to 2965) WL#3726
View as plain text  
 2965 Konstantin Osipov	2009-12-01
      Backport of:
      ------------------------------------------------------------
      revno: 2630.9.2
      committer: Dmitry Lenev <dlenev@stripped>
      branch nick: mysql-6.0-3726-w3
      timestamp: Tue 2008-06-10 18:01:56 +0400
      message:
        WL#3726 "DDL locking for all metadata objects".
      
        After review fixes in progress.
     @ sql/mdl.cc
        Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
        as one of arguments as described in specification.
     @ sql/mdl.h
        Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
         as one of arguments as described in specification.
     @ sql/sql_base.cc
        Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
        as one of arguments as described in specification.
        Renamed handle_failed_open_table_attempt() to
        recover_from_failed_open_table_attempt() as suggested by review.
        Added comment clarifying why we need to check TABLE::db_stat
        while looking at TABLE instances open by other threads.
     @ sql/sql_show.cc
        Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
        as one of arguments as described in specification.

    modified:
      sql/mdl.cc
      sql/mdl.h
      sql/sql_base.cc
      sql/sql_show.cc
 2964 Konstantin Osipov	2009-12-01
      Backport of:
      ------------------------------------------------------------ 
      revno: 2630.9.1 
      committer: Dmitry Lenev <dlenev@stripped> 
      branch nick: mysql-6.0-3726-w3 
      timestamp: Sun 2008-06-08 22:13:58 +0400 
      message: 
        WL#3726 "DDL locking for all metadata objects" 
         
        After review fixes in progress. 
         
        Some adjustments to the patch that removes thd->locked_tables
     @ sql/sp_head.cc
        Fix conditions which were wrongly translated by previous patch.
     @ sql/sql_base.cc
        close_thread_tables():
          Add comment clarifying control flow in case of LTM_LOCK_TABLES
          mode and statements requiring prelocking.
          Be consistent with other places where we clear
          OPTION_TABLE_LOCK flag.
        lock_tables():
          Always set THD::lock to 0 after freeing memory to which it
          points.

    modified:
      sql/sp_head.cc
      sql/sql_base.cc
 2963 Konstantin Osipov	2009-12-01
      Backport of:
      ------------------------------------------------------------
      revno: 2630.4.27
      committer: Dmitry Lenev <dlenev@stripped>
      branch nick: mysql-6.0-3726-w2
      timestamp: Mon 2008-06-09 14:01:19 +0400
      message:
        WL#3726 "DDL locking for all metadata objects".
      
        After review fixes in progress.
      
        Changed open_table() to return bool. This allows more easily to
        distinguish cases when this function succeeds but returns no TABLE
        instance (in case of view or in case of special kind of open) from
        cases when we have an error. Pointer to TABLE instance is now
        always returned in TABLE_LIST::table member.
      
        This change allows to get rid of false assumption in open_tables()
        implementation and makes it more clear.

    modified:
      sql/mysql_priv.h
      sql/sql_base.cc
      sql/sql_insert.cc
      sql/sql_table.cc
 2962 Konstantin Osipov	2009-12-01
      Backport of:
      ----------------------------------------------------------
      revno: 2630.4.26
      committer: Konstantin Osipov <konstantin@stripped>
      branch nick: mysql-6.0-prelocked_mode-to-push
      timestamp: Fri 2008-06-06 23:19:04 +0400
      message:
        WL#3726: work on review comments.
        Remove thd->locked_tables. Always store MYSQL_LOCK instances in
        thd->lock.
        Rename thd->prelocked_mode to thd->locked_tables_mode.
        Use thd->locked_tables_mode to determine if we
        are under LOCK TABLES. Update the code to not assume that
        if thd->lock is set, LOCK TABLES mode is off.
        Review comments.
     @ sql/ha_ndbcluster_binlog.cc
        Don't unlock the lock under LOCK TABLES (safety).
     @ sql/handler.cc
        There is no thd->locked_tables any more.
        Update comments.
     @ sql/lock.cc
        There is no thd->locked_tables any more.
     @ sql/log.cc
        Rename thd->prelocked_mode to thd->locked_tables_mode.
     @ sql/set_var.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sp_head.cc
        Rename thd->prelocked_mode to thd->locked_tables_mode.
     @ sql/sql_base.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
        Remove thd->locked_tables.
     @ sql/sql_cache.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_class.cc
        Avoid code duplication.
        Do not release the table locks prematurely if we're under LOCK TABLES.
        Use thd->locked_tables_mode instead of thd->locked_tables.
     @ sql/sql_class.h
        Remove thd->locked_tables.
        Make prelocked mode a kind of LOCK TABLES mode.
        Update comments.
     @ sql/sql_cursor.cc
        Update comments.
     @ sql/sql_insert.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
        Rename thd->prelocked_mode to thd->locked_tables_mode.
     @ sql/sql_load.cc
        Rename thd->prelocked_mode to thd->locked_tables_mode.
     @ sql/sql_parse.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
        Remove thd->locked_tables.
     @ sql/sql_partition.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_rename.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_select.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_table.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_trigger.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_update.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ sql/sql_view.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
     @ storage/myisam/ha_myisam.cc
        Use thd->locked_tables_mode to determine if we are under LOCK TABLES.

    modified:
      sql/ha_ndbcluster_binlog.cc
      sql/handler.cc
      sql/lock.cc
      sql/log.cc
      sql/set_var.cc
      sql/sp_head.cc
      sql/sql_base.cc
      sql/sql_cache.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_cursor.cc
      sql/sql_insert.cc
      sql/sql_load.cc
      sql/sql_parse.cc
      sql/sql_partition.cc
      sql/sql_rename.cc
      sql/sql_select.cc
      sql/sql_table.cc
      sql/sql_trigger.cc
      sql/sql_update.cc
      sql/sql_view.cc
      storage/myisam/ha_myisam.cc
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2009-12-01 13:59:11 +0000
+++ b/sql/mdl.cc	2009-12-01 15:20:43 +0000
@@ -611,6 +611,7 @@ static bool can_grant_lock(MDL_LOCK *loc
 
    This function must be called after the lock is added to a context.
 
+   @param context    [in]  Context containing request for lock
    @param lock_data  [in]  Lock request object for lock to be acquired
    @param retry      [out] Indicates that conflicting lock exists and another
                            attempt should be made after releasing all current
@@ -622,16 +623,19 @@ static bool can_grant_lock(MDL_LOCK *loc
                     In the latter case "retry" parameter is set to TRUE.
 */
 
-bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry)
+bool mdl_acquire_shared_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data,
+                             bool *retry)
 {
   MDL_LOCK *lock;
   *retry= FALSE;
 
   DBUG_ASSERT(is_shared(lock_data) && lock_data->state == MDL_PENDING);
 
+  DBUG_ASSERT(lock_data->ctx == context);
+
   safe_mutex_assert_not_owner(&LOCK_open);
 
-  if (lock_data->ctx->has_global_shared_lock &&
+  if (context->has_global_shared_lock &&
       lock_data->type == MDL_SHARED_UPGRADABLE)
   {
     my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));

=== modified file 'sql/mdl.h'
--- a/sql/mdl.h	2009-12-01 13:59:11 +0000
+++ b/sql/mdl.h	2009-12-01 15:20:43 +0000
@@ -164,7 +164,8 @@ inline void mdl_set_lock_type(MDL_LOCK_D
   lock_data->type= lock_type;
 }
 
-bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry);
+bool mdl_acquire_shared_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data,
+                             bool *retry);
 bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context);
 bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
                                           MDL_LOCK_DATA *lock_data);

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-12-01 13:38:00 +0000
+++ b/sql/mysql_priv.h	2009-12-01 14:58:31 +0000
@@ -1220,8 +1220,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
                    uint lock_flags);
 enum enum_open_table_action {OT_NO_ACTION= 0, OT_BACK_OFF_AND_RETRY,
                              OT_DISCOVER, OT_REPAIR};
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
-		  enum_open_table_action *action, uint flags);
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
+                enum_open_table_action *action, uint flags);
 bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
                    char *cache_key, uint cache_key_length,
                    MEM_ROOT *mem_root, uint flags);

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2009-12-01 14:39:03 +0000
+++ b/sql/sp_head.cc	2009-12-01 15:04:32 +0000
@@ -1257,7 +1257,7 @@ sp_head::execute(THD *thd)
       Will write this SP statement into binlog separately 
       (TODO: consider changing the condition to "not inside event union")
     */
-    if (thd->locked_tables_mode == LTM_NONE)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
       thd->user_var_events_alloc= thd->mem_root;
 
     err_status= i->execute(thd, &ip);
@@ -1269,7 +1269,7 @@ sp_head::execute(THD *thd)
       If we've set thd->user_var_events_alloc to mem_root of this SP
       statement, clean all the events allocated in it.
     */
-    if (thd->locked_tables_mode == LTM_NONE)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
     {
       reset_dynamic(&thd->user_var_events);
       thd->user_var_events_alloc= NULL;//DEBUG
@@ -2740,7 +2740,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
   thd->query_id= next_query_id();
   pthread_mutex_unlock(&LOCK_thread_count);
 
-  if (thd->locked_tables_mode == LTM_NONE)
+  if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
   {
     /*
       This statement will enter/leave prelocked mode on its own.

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-12-01 14:39:03 +0000
+++ b/sql/sql_base.cc	2009-12-01 15:20:43 +0000
@@ -1375,6 +1375,7 @@ void close_thread_tables(THD *thd,
                          bool skip_mdl)
 {
   TABLE *table;
+  bool clear_table_lock_option= FALSE;
   DBUG_ENTER("close_thread_tables");
 
 #ifdef EXTRA_DEBUG
@@ -1446,6 +1447,11 @@ void close_thread_tables(THD *thd,
     /*
       We are under simple LOCK TABLES or we're inside a sub-statement
       of a prelocked statement, so should not do anything else.
+
+      Note that even if we are in LTM_LOCK_TABLES mode and statement
+      requires prelocking (e.g. when we are closing tables after
+      failing ot "open" all tables required for statement execution)
+      we will exit this function a few lines below.
     */
     if (! thd->lex->requires_prelocking())
       DBUG_VOID_RETURN;
@@ -1462,7 +1468,7 @@ void close_thread_tables(THD *thd,
       DBUG_VOID_RETURN;
 
     thd->locked_tables_mode= LTM_NONE;
-    thd->options&= ~OPTION_TABLE_LOCK;
+    clear_table_lock_option= TRUE;
 
     /*
       Note that we are leaving prelocked mode so we don't need
@@ -1502,6 +1508,9 @@ void close_thread_tables(THD *thd,
     mdl_remove_all_locks(&thd->mdl_context);
   }
 
+  if (clear_table_lock_option)
+    thd->options&= ~OPTION_TABLE_LOCK;
+
   DBUG_VOID_RETURN;
 }
 
@@ -2574,8 +2583,6 @@ void table_share_release_hook(void *shar
                         which will be set according to action which is
                         required to remedy problem appeared during attempt
                         to open table.
-                        If this is a NULL pointer, then the table is not
-                        put in the thread-open-list.
     flags               Bitmap of flags to modify how open works:
                           MYSQL_LOCK_IGNORE_FLUSH - Open table even if
                           someone has done a flush or there is a pending
@@ -2597,14 +2604,16 @@ void table_share_release_hook(void *shar
     "open_type" is TAKE_EXCLUSIVE_MDL.
 
   RETURN
-    NULL  Open failed.  If refresh is set then one should close
-          all other tables and retry the open.
-    #     Success. Pointer to TABLE object for open table.
+    TRUE  Open failed. "action" parameter may contain type of action
+          needed to remedy problem before retrying again.
+    FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
+          TABLE_LIST::table is set for real tables and TABLE_LIST::view is
+          set for views).
 */
 
 
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
-		  enum_open_table_action *action, uint flags)
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+                enum_open_table_action *action, uint flags)
 {
   reg1	TABLE *table;
   char	key[MAX_DBKEY_LENGTH];
@@ -2622,10 +2631,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *
 
   /* an open table operation needs a lot of the stack space */
   if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
-    DBUG_RETURN(0);
+    DBUG_RETURN(TRUE);
 
   if (thd->killed)
-    DBUG_RETURN(0);
+    DBUG_RETURN(TRUE);
 
   key_length= (create_table_def_key(thd, key, table_list, 1) -
                TMP_TABLE_KEY_EXTRA);
@@ -2659,7 +2668,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
                       (ulong) table->query_id, (uint) thd->server_id,
                       (ulong) thd->variables.pseudo_thread_id));
 	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
-	  DBUG_RETURN(0);
+	  DBUG_RETURN(TRUE);
 	}
 	table->query_id= thd->query_id;
 	thd->thread_specific_used= TRUE;
@@ -2672,7 +2681,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
   if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
   {
     my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
-    DBUG_RETURN(0);
+    DBUG_RETURN(TRUE);
   }
 
   /*
@@ -2770,7 +2779,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
                            mem_root, 0))
         {
           DBUG_ASSERT(table_list->view != 0);
-          DBUG_RETURN(0); // VIEW
+          DBUG_RETURN(FALSE); // VIEW
         }
       }
     }
@@ -2785,7 +2794,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
       my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
     else
       my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
-    DBUG_RETURN(0);
+    DBUG_RETURN(TRUE);
   }
 
   /*
@@ -2809,7 +2818,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
     */
     mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
     if (mdl_acquire_exclusive_locks(&thd->mdl_context))
-      DBUG_RETURN(0);
+      DBUG_RETURN(TRUE);
   }
   else
   {
@@ -2828,11 +2837,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *
     if (flags & MYSQL_LOCK_IGNORE_FLUSH)
       mdl_set_lock_type(mdl_lock_data, MDL_SHARED_HIGH_PRIO);
 
-    if (mdl_acquire_shared_lock(mdl_lock_data, &retry))
+    if (mdl_acquire_shared_lock(&thd->mdl_context, mdl_lock_data, &retry))
     {
       if (retry)
         *action= OT_BACK_OFF_AND_RETRY;
-      DBUG_RETURN(0);
+      DBUG_RETURN(TRUE);
     }
   }
 
@@ -2854,7 +2863,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
     /* Someone did a refresh while thread was opening tables */
     *action= OT_BACK_OFF_AND_RETRY;
     pthread_mutex_unlock(&LOCK_open);
-    DBUG_RETURN(0);
+    DBUG_RETURN(TRUE);
   }
 
   if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
@@ -2867,14 +2876,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *
     if (!exists)
     {
       pthread_mutex_unlock(&LOCK_open);
-      DBUG_RETURN(0);
+      DBUG_RETURN(FALSE);
     }
     /* Table exists. Let us try to open it. */
   }
   else if (table_list->open_type == TABLE_LIST::TAKE_EXCLUSIVE_MDL)
   {
     pthread_mutex_unlock(&LOCK_open);
-    DBUG_RETURN(0);
+    DBUG_RETURN(FALSE);
   }
 
   if (!(share= (TABLE_SHARE *)mdl_get_cached_object(mdl_lock_data)))
@@ -2921,28 +2930,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *
       }
 
       pthread_mutex_unlock(&LOCK_open);
-      DBUG_RETURN(0);
-    }
-    else if (table_list->view)
-    {
-      /*
-        We're trying to open a table for what was a view.
-        This can only happen during (re-)execution.
-        At prepared statement prepare the view has been opened and
-        merged into the statement parse tree. After that, someone
-        performed a DDL and replaced the view with a base table.
-        Don't try to open the table inside a prepared statement,
-        invalidate it instead.
-
-        Note, the assert below is known to fail inside stored
-        procedures (Bug#27011).
-      */
-      DBUG_ASSERT(thd->m_reprepare_observer);
-      check_and_update_table_version(thd, table_list, share);
-      /* Always an error. */
-      DBUG_ASSERT(thd->is_error());
-      goto err_unlock;
+      DBUG_RETURN(FALSE);
     }
+    /*
+      Note that situation when we are trying to open a table for what
+      was a view during previous execution of PS will be handled in by
+      the caller. Here we should simply open our table even if
+      TABLE_LIST::view is true.
+    */
 
     if (table_list->i_s_requested_object &  OPEN_VIEW_ONLY)
       goto err_unlock;
@@ -2992,7 +2987,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
       *action= OT_BACK_OFF_AND_RETRY;
       release_table_share(share);
       pthread_mutex_unlock(&LOCK_open);
-      DBUG_RETURN(0);
+      DBUG_RETURN(TRUE);
     }
     /* Force close at once after usage */
     thd->version= share->version;
@@ -3103,15 +3098,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *
   table->pos_in_table_list= table_list;
   table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
   table->clear_column_bitmaps();
+  table_list->table= table;
   DBUG_ASSERT(table->key_read == 0);
-  DBUG_RETURN(table);
+  DBUG_RETURN(FALSE);
 
 err_unlock:
   release_table_share(share);
 err_unlock2:
   pthread_mutex_unlock(&LOCK_open);
   mdl_release_lock(&thd->mdl_context, mdl_lock_data);
-  DBUG_RETURN(0);
+  DBUG_RETURN(TRUE);
 }
 
 
@@ -4048,18 +4044,21 @@ end_with_lock_open:
 
 
 /**
-   Handle failed attempt ot open table by performing requested action.
+   Recover from failed attempt ot open table by performing requested action.
 
    @param  thd     Thread context
    @param  table   Table list element for table that caused problem
    @param  action  Type of action requested by failed open_table() call
 
+   @pre This function should be called only with "action" != OT_NO_ACTION.
+
    @retval FALSE - Success. One should try to open tables once again.
    @retval TRUE  - Error
 */
 
-static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
-                                             enum_open_table_action action)
+static bool
+recover_from_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
+                                       enum_open_table_action action)
 {
   bool result= FALSE;
 
@@ -4502,6 +4501,7 @@ int open_tables(THD *thd, TABLE_LIST **s
   TABLE_LIST *tables= NULL;
   enum_open_table_action action;
   int result=0;
+  bool error;
   MEM_ROOT new_frm_mem;
   /* Also used for indicating that prelocking is need */
   TABLE_LIST **query_tables_last_own;
@@ -4620,64 +4620,30 @@ int open_tables(THD *thd, TABLE_LIST **s
                           tables->db, tables->table_name, (long) tables));
     (*counter)++;
 
-    /*
-      Not a placeholder: must be a base table or a view, and the table is
-      not opened yet. Try to open the table.
-    */
-    if (!tables->table)
+    /* Not a placeholder: must be a base table or a view. Let us open it. */
+    DBUG_ASSERT(!tables->table);
+
+    if (tables->prelocking_placeholder)
     {
-      if (tables->prelocking_placeholder)
-      {
-        /*
-          For the tables added by the pre-locking code, attempt to open
-          the table but fail silently if the table does not exist.
-          The real failure will occur when/if a statement attempts to use
-          that table.
-        */
-        Prelock_error_handler prelock_handler;
-        thd->push_internal_handler(& prelock_handler);
-        tables->table= open_table(thd, tables, &new_frm_mem, &action, flags);
-        thd->pop_internal_handler();
-        safe_to_ignore_table= prelock_handler.safely_trapped_errors();
-      }
-      else
-        tables->table= open_table(thd, tables, &new_frm_mem, &action, flags);
+      /*
+        For the tables added by the pre-locking code, attempt to open
+        the table but fail silently if the table does not exist.
+        The real failure will occur when/if a statement attempts to use
+        that table.
+      */
+      Prelock_error_handler prelock_handler;
+      thd->push_internal_handler(& prelock_handler);
+      error= open_table(thd, tables, &new_frm_mem, &action, flags);
+      thd->pop_internal_handler();
+      safe_to_ignore_table= prelock_handler.safely_trapped_errors();
     }
     else
-      DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx",
-                            tables->db, tables->table_name,
-                            (long) tables->table));
+      error= open_table(thd, tables, &new_frm_mem, &action, flags);
 
-    if (!tables->table)
-    {
-      free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
-
-      if (tables->view)
-      {
-        /* VIEW placeholder */
-	(*counter)--;
-
-        /*
-          tables->next_global list consists of two parts:
-          1) Query tables and underlying tables of views.
-          2) Tables used by all stored routines that this statement invokes on
-             execution.
-          We need to know where the bound between these two parts is. If we've
-          just opened a view, which was the last table in part #1, and it
-          has added its base tables after itself, adjust the boundary pointer
-          accordingly.
-        */
-        if (query_tables_last_own == &(tables->next_global) &&
-            tables->view->query_tables)
-          query_tables_last_own= tables->view->query_tables_last;
-        /*
-          Let us free memory used by 'sroutines' hash here since we never
-          call destructor for this LEX.
-        */
-        my_hash_free(&tables->view->sroutines);
-	goto process_view_routines;
-      }
+    free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
 
+    if (error)
+    {
       /*
         If in a MERGE table open, we need to remove the children list
         from statement table list before restarting. Otherwise the list
@@ -4691,15 +4657,6 @@ int open_tables(THD *thd, TABLE_LIST **s
         parent_l->next_global= *parent_l->table->child_last_l;
       }
 
-      /*
-        FIXME This is a temporary hack. Actually we need check that will
-        allow us to differentiate between error while opening/creating
-        table and successful table creation.
-        ...
-      */
-      if (tables->open_type)
-        continue;
-
       if (action)
       {
         /*
@@ -4724,7 +4681,7 @@ int open_tables(THD *thd, TABLE_LIST **s
           TABLE_LIST element. Altough currently this assumption is valid
           it may change in future.
         */
-        if (handle_failed_open_table_attempt(thd, tables, action))
+        if (recover_from_failed_open_table_attempt(thd, tables, action))
         {
           result= -1;
           goto err;
@@ -4742,36 +4699,73 @@ int open_tables(THD *thd, TABLE_LIST **s
       result= -1;				// Fatal error
       break;
     }
-    else
+
+    /*
+      We can't rely on simple check for TABLE_LIST::view to determine
+      that this is a view since during re-execution we might reopen
+      ordinary table in place of view and thus have TABLE_LIST::view
+      set from repvious execution and TABLE_LIST::table set from
+      current.
+    */
+    if (!tables->table && tables->view)
     {
+      /* VIEW placeholder */
+      (*counter)--;
+
       /*
-        If we are not already in prelocked mode and extended table list is not
-        yet built and we have trigger for table being opened then we should
-        cache all routines used by its triggers and add their tables to
-        prelocking list.
-        If we lock table for reading we won't update it so there is no need to
-        process its triggers since they never will be activated.
+        tables->next_global list consists of two parts:
+        1) Query tables and underlying tables of views.
+        2) Tables used by all stored routines that this statement invokes on
+           execution.
+        We need to know where the bound between these two parts is. If we've
+        just opened a view, which was the last table in part #1, and it
+        has added its base tables after itself, adjust the boundary pointer
+        accordingly.
       */
-      if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
-          !thd->lex->requires_prelocking() &&
-          tables->trg_event_map && tables->table->triggers &&
-          tables->lock_type >= TL_WRITE_ALLOW_WRITE)
-      {
-        if (!query_tables_last_own)
-          query_tables_last_own= thd->lex->query_tables_last;
-        if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
-                                                          tables))
-        {
-          /*
-            Serious error during reading stored routines from mysql.proc table.
-            Something's wrong with the table or its contents, and an error has
-            been emitted; we must abort.
-          */
-          result= -1;
-          goto err;
-        }
+      if (query_tables_last_own == &(tables->next_global) &&
+          tables->view->query_tables)
+        query_tables_last_own= tables->view->query_tables_last;
+      /*
+        Let us free memory used by 'sroutines' hash here since we never
+        call destructor for this LEX.
+      */
+      my_hash_free(&tables->view->sroutines);
+      goto process_view_routines;
+    }
+
+    /*
+      Special types of open can succeed but still don't set
+      TABLE_LIST::table to anything.
+    */
+    if (tables->open_type && !tables->table)
+      continue;
+
+    /*
+      If we are not already in prelocked mode and extended table list is not
+      yet built and we have trigger for table being opened then we should
+      cache all routines used by its triggers and add their tables to
+      prelocking list.
+      If we lock table for reading we won't update it so there is no need to
+      process its triggers since they never will be activated.
+    */
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+        !thd->lex->requires_prelocking() &&
+        tables->trg_event_map && tables->table->triggers &&
+        tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+    {
+      if (!query_tables_last_own)
+        query_tables_last_own= thd->lex->query_tables_last;
+      if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
+                                                        tables))
+      {
+        /*
+          Serious error during reading stored routines from mysql.proc table.
+          Something's wrong with the table or its contents, and an error has
+          been emitted; we must abort.
+        */
+        result= -1;
+        goto err;
       }
-      free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
     }
 
     if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
@@ -4985,6 +4979,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
   TABLE *table;
   enum_open_table_action action;
   bool refresh;
+  bool error;
   DBUG_ENTER("open_ltable");
 
   /* should not be used in a prelocked_mode context, see NOTE above */
@@ -4996,7 +4991,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST 
   table_list->required_type= FRMTYPE_TABLE;
 
 retry:
-  while (!(table= open_table(thd, table_list, thd->mem_root, &action, 0)) &&
+  while ((error= open_table(thd, table_list, thd->mem_root, &action, 0)) &&
          action)
   {
     /*
@@ -5005,12 +5000,18 @@ retry:
       might have been acquired successfully.
     */
     close_thread_tables(thd, (action == OT_BACK_OFF_AND_RETRY));
-    if (handle_failed_open_table_attempt(thd, table_list, action))
+    if (recover_from_failed_open_table_attempt(thd, table_list, action))
       break;
   }
 
-  if (table)
+  if (!error)
   {
+    /*
+      We can't have a view or some special "open_type" in this function
+      so there should be a TABLE instance.
+    */
+    DBUG_ASSERT(table_list->table);
+    table= table_list->table;
     if (table->child_l)
     {
       /* A MERGE table must not come here. */
@@ -5023,7 +5024,6 @@ retry:
     }
 
     table_list->lock_type= lock_type;
-    table_list->table=	   table;
     table->grant= table_list->grant;
     if (thd->locked_tables_mode)
     {
@@ -5047,6 +5047,8 @@ retry:
         }
     }
   }
+  else
+    table= 0;
 
  end:
   thd_proc_info(thd, 0);
@@ -5462,6 +5464,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
               need to care about THD::locked_tables_root here.
             */
             mysql_unlock_tables(thd, thd->lock);
+            thd->lock= 0;
             thd->options&= ~(OPTION_TABLE_LOCK);
             DBUG_RETURN(-1);
           }
@@ -8530,7 +8533,13 @@ bool notify_thread_having_shared_lock(TH
        thd_table ;
        thd_table= thd_table->next)
   {
-    /* TODO With new MDL check for db_stat is probably a legacy */
+    /*
+      Check for TABLE::db_stat is needed since in some places we call
+      handler::close() for table instance (and set TABLE::db_stat to 0)
+      and do not remove such instances from the THD::open_tables
+      for some time, during which other thread can see those instances
+      (e.g. see partitioning code).
+    */
     if (thd_table->db_stat)
       signalled|= mysql_lock_abort_for_thread(thd, thd_table);
   }

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2009-12-01 14:39:03 +0000
+++ b/sql/sql_insert.cc	2009-12-01 14:58:31 +0000
@@ -3555,8 +3555,8 @@ static TABLE *create_table_from_items(TH
       }
       else
       {
-        if (!(table= open_table(thd, create_table, thd->mem_root, &not_used2,
-                                MYSQL_OPEN_TEMPORARY_ONLY)) &&
+        if (open_table(thd, create_table, thd->mem_root, &not_used2,
+                       MYSQL_OPEN_TEMPORARY_ONLY) &&
             !create_info->table_existed)
         {
           /*
@@ -3566,6 +3566,8 @@ static TABLE *create_table_from_items(TH
           */
           drop_temporary_table(thd, create_table);
         }
+        else
+          table= create_table->table;
       }
     }
     reenable_binlog(thd);

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2009-12-01 13:59:11 +0000
+++ b/sql/sql_show.cc	2009-12-01 15:20:43 +0000
@@ -3145,7 +3145,7 @@ static int fill_schema_table_from_frm(TH
   */
   while (1)
   {
-    if (mdl_acquire_shared_lock(&mdl_lock_data, &retry))
+    if (mdl_acquire_shared_lock(&thd->mdl_context, &mdl_lock_data, &retry))
     {
       if (!retry || mdl_wait_for_locks(&thd->mdl_context))
       {

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-12-01 14:39:03 +0000
+++ b/sql/sql_table.cc	2009-12-01 14:58:31 +0000
@@ -7182,8 +7182,9 @@ view_err:
       tbl.db= new_db;
       tbl.table_name= tbl.alias= tmp_name;
       /* Table is in thd->temporary_tables */
-      new_table= open_table(thd, &tbl, thd->mem_root, &not_used,
-                            MYSQL_LOCK_IGNORE_FLUSH);
+      (void) open_table(thd, &tbl, thd->mem_root, &not_used,
+                        MYSQL_LOCK_IGNORE_FLUSH);
+      new_table= tbl.table;
     }
     else
     {


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091201152043-zykxllat23hxrkcm.bundle
Thread
bzr push into mysql-5.6-next-mr branch (kostja:2962 to 2965) WL#3726Konstantin Osipov1 Dec