List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:June 6 2008 7:17pm
Subject:bzr commit into mysql-6.0 branch (konstantin:2662) WL#3726
View as plain text  
#At file:///opt/local/work/mysql-6.0-prelocked_mode-to-push/

 2662 Konstantin Osipov	2008-06-06
      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.
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

per-file 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 file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2008-06-03 17:41:59 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2008-06-06 19:17:47 +0000
@@ -270,7 +270,7 @@ static void run_query(THD *thd, char *bu
   DBUG_PRINT("query", ("%s", thd->query));
 
   DBUG_ASSERT(!thd->in_sub_stmt);
-  DBUG_ASSERT(!thd->prelocked_mode);
+  DBUG_ASSERT(!thd->locked_tables_mode);
 
   mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
 
@@ -2625,8 +2625,12 @@ ndb_add_ndb_binlog_index(THD *thd, ndb_b
     }
   } while (row);
 
-  mysql_unlock_tables(thd, thd->lock);
-  thd->lock= 0;
+
+  if (! thd->locked_tables_mode)                /* Is always TRUE */
+  {
+    mysql_unlock_tables(thd, thd->lock);
+    thd->lock= 0;
+  }
   thd->options= saved_options;
   return 0;
 add_ndb_binlog_index_err:

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-05-27 10:44:38 +0000
+++ b/sql/handler.cc	2008-06-06 19:17:47 +0000
@@ -5165,9 +5165,7 @@ static bool check_table_binlog_row_based
    to the binary log.
 
    This function will generate and write table maps for all tables
-   that are locked by the thread 'thd'.  Either manually locked
-   (stored in THD::locked_tables) and automatically locked (stored
-   in THD::lock) are considered.
+   that are locked by the thread 'thd'.
 
    @param thd     Pointer to THD structure
 
@@ -5176,23 +5174,19 @@ static bool check_table_binlog_row_based
 
    @sa
        THD::lock
-       THD::locked_tables
 */
 
 static int write_locked_table_maps(THD *thd)
 {
   DBUG_ENTER("write_locked_table_maps");
-  DBUG_PRINT("enter", ("thd: %p  thd->lock: %p  thd->locked_tables: %p  "
-                       "thd->extra_lock: %p",
-                       thd, thd->lock,
-                       thd->locked_tables, thd->extra_lock));
+  DBUG_PRINT("enter", ("thd: %p  thd->lock: %p thd->extra_lock: %p",
+                       thd, thd->lock, thd->extra_lock));
 
   if (thd->get_binlog_table_maps() == 0)
   {
-    MYSQL_LOCK *locks[3];
+    MYSQL_LOCK *locks[2];
     locks[0]= thd->extra_lock;
     locks[1]= thd->lock;
-    locks[2]= thd->locked_tables;
     for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
     {
       MYSQL_LOCK const *const lock= locks[i];

=== modified file 'sql/lock.cc'
--- a/sql/lock.cc	2008-06-03 17:07:58 +0000
+++ b/sql/lock.cc	2008-06-06 19:17:47 +0000
@@ -739,7 +739,7 @@ TABLE_LIST *mysql_lock_have_duplicate(TH
     goto end;
 
   /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
-  if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
+  if (! (mylock= thd->lock))
     goto end;
 
   /* If we have less than two tables, we cannot have duplicates. */

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2008-05-21 19:46:08 +0000
+++ b/sql/log.cc	2008-06-06 19:17:47 +0000
@@ -3850,7 +3850,7 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
     this will close all tables on the slave.
   */
   bool const end_stmt=
-    thd->prelocked_mode && thd->lex->requires_prelocking();
+    thd->locked_tables_mode && thd->lex->requires_prelocking();
   thd->binlog_flush_pending_rows_event(end_stmt);
 
   pthread_mutex_lock(&LOCK_log);

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2008-05-23 13:54:03 +0000
+++ b/sql/set_var.cc	2008-06-06 19:17:47 +0000
@@ -4005,7 +4005,7 @@ bool sys_var_opt_readonly::update(THD *t
   DBUG_ENTER("sys_var_opt_readonly::update");
 
   /* Prevent self dead-lock */
-  if (thd->locked_tables || thd->active_transaction())
+  if (thd->locked_tables_mode || thd->active_transaction())
   {
     my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
     DBUG_RETURN(true);

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2008-05-29 12:52:56 +0000
+++ b/sql/sp_head.cc	2008-06-06 19:17:47 +0000
@@ -1233,7 +1233,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->prelocked_mode == NON_PRELOCKED)
+    if (thd->locked_tables_mode == LTM_NONE)
       thd->user_var_events_alloc= thd->mem_root;
 
     err_status= i->execute(thd, &ip);
@@ -1245,7 +1245,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->prelocked_mode == NON_PRELOCKED)
+    if (thd->locked_tables_mode == LTM_NONE)
     {
       reset_dynamic(&thd->user_var_events);
       thd->user_var_events_alloc= NULL;//DEBUG
@@ -2687,7 +2687,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
   thd->query_id= next_query_id();
   pthread_mutex_unlock(&LOCK_thread_count);
 
-  if (thd->prelocked_mode == NON_PRELOCKED)
+  if (thd->locked_tables_mode == LTM_NONE)
   {
     /*
       This statement will enter/leave prelocked mode on its own.

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-06-05 15:33:38 +0000
+++ b/sql/sql_base.cc	2008-06-06 19:17:47 +0000
@@ -1001,7 +1001,7 @@ bool close_cached_tables(THD *thd, TABLE
   DBUG_ASSERT(!have_lock);
   pthread_mutex_unlock(&LOCK_open);
 
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     /*
       If we are under LOCK TABLES we need to reopen tables without
@@ -1115,7 +1115,7 @@ bool close_cached_tables(THD *thd, TABLE
   }
 
 err_with_reopen:
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     pthread_mutex_lock(&LOCK_open);
     /*
@@ -1328,7 +1328,6 @@ void close_thread_tables(THD *thd,
                          bool skip_mdl)
 {
   TABLE *table;
-  prelocked_mode_type prelocked_mode= thd->prelocked_mode;
   DBUG_ENTER("close_thread_tables");
 
 #ifdef EXTRA_DEBUG
@@ -1386,11 +1385,12 @@ void close_thread_tables(THD *thd,
       Reset transaction state, but only if we're not inside a
       sub-statement of a prelocked statement.
     */
-    if (! prelocked_mode || thd->lex->requires_prelocking())
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
+        thd->lex->requires_prelocking())
       thd->transaction.stmt.reset();
   }
 
-  if (thd->locked_tables || prelocked_mode)
+  if (thd->locked_tables_mode)
   {
 
     /* Ensure we are calling ha_reset() for all used tables */
@@ -1400,7 +1400,7 @@ 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.
     */
-    if (!prelocked_mode || !thd->lex->requires_prelocking())
+    if (! thd->lex->requires_prelocking())
       DBUG_VOID_RETURN;
 
     /*
@@ -1408,18 +1408,19 @@ void close_thread_tables(THD *thd,
       so we have to leave the prelocked mode now with doing implicit
       UNLOCK TABLES if needed.
     */
-    DBUG_PRINT("info",("thd->prelocked_mode= NON_PRELOCKED"));
-    thd->prelocked_mode= NON_PRELOCKED;
+    if (thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
+      thd->locked_tables_mode= LTM_LOCK_TABLES;
 
-    if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
+    if (thd->locked_tables_mode == LTM_LOCK_TABLES)
       DBUG_VOID_RETURN;
 
+    thd->locked_tables_mode= LTM_NONE;
+    thd->options&= ~OPTION_TABLE_LOCK;
+
     /*
       Note that we are leaving prelocked mode so we don't need
       to care about THD::locked_tables_root.
     */
-    thd->lock= thd->locked_tables;
-    thd->locked_tables= 0;
     /* Fallthrough */
   }
 
@@ -1454,16 +1455,6 @@ void close_thread_tables(THD *thd,
     mdl_remove_all_locks(&thd->mdl_context);
   }
 
-  if (prelocked_mode == PRELOCKED)
-  {
-    /*
-      If we are here then we are leaving normal prelocked mode, so it is
-      good idea to turn off OPTION_TABLE_LOCK flag.
-    */
-    DBUG_ASSERT(thd->lex->requires_prelocking());
-    thd->options&= ~(OPTION_TABLE_LOCK);
-  }
-
   DBUG_VOID_RETURN;
 }
 
@@ -1887,9 +1878,10 @@ TABLE *find_temporary_table(THD *thd, TA
   Try to locate the table in the list of thd->temporary_tables.
   If the table is found:
    - if the table is being used by some outer statement, fail.
-   - if the table is in thd->locked_tables, unlock it and
-     remove it from the list of locked tables. Currently only transactional
-     temporary tables are present in the locked_tables list.
+   - if the table is locked with LOCK TABLES or by prelocking,
+   unlock it and remove it from the list of locked tables
+   (THD::lock). Currently only transactional temporary tables
+   are locked.
    - Close the temporary table, remove its .FRM
    - remove the table from the list of temporary tables
 
@@ -1928,7 +1920,7 @@ int drop_temporary_table(THD *thd, TABLE
     If LOCK TABLES list is not empty and contains this table,
     unlock the table and remove the table from this list.
   */
-  mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
+  mysql_lock_remove(thd, thd->lock, table, FALSE);
   close_temporary_table(thd, table, 1, 1);
   DBUG_RETURN(0);
 }
@@ -2206,7 +2198,7 @@ bool close_cached_table(THD *thd, TABLE 
     DBUG_RETURN(TRUE);
 
   /* Close lock if this is not got with LOCK TABLES */
-  if (thd->lock)
+  if (! thd->locked_tables_mode)
   {
     mysql_unlock_tables(thd, thd->lock);
     thd->lock=0;			// Start locked threads
@@ -2258,8 +2250,8 @@ void unlink_open_table(THD *thd, TABLE *
     if (list->s->table_cache_key.length == key_length &&
 	!memcmp(list->s->table_cache_key.str, key, key_length))
     {
-      if (unlock && thd->locked_tables)
-        mysql_lock_remove(thd, thd->locked_tables,
+      if (unlock && thd->locked_tables_mode)
+        mysql_lock_remove(thd, thd->lock,
                           list->parent ? list->parent : list, TRUE);
 
       /* Prepare MERGE table for close. Close parent if necessary. */
@@ -2629,11 +2621,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *
     open not pre-opened tables in pre-locked/LOCK TABLES mode.
     TODO: move this block into a separate function.
   */
-  if (thd->locked_tables || thd->prelocked_mode)
+  if (thd->locked_tables_mode)
   {						// Using table locks
     TABLE *best_table= 0;
     int best_distance= INT_MIN;
-    bool check_if_used= thd->prelocked_mode &&
+    bool check_if_used= thd->locked_tables_mode > LTM_LOCK_TABLES &&
                         ((int) table_list->lock_type >=
                          (int) TL_WRITE_ALLOW_WRITE);
     for (table=thd->open_tables; table ; table=table->next)
@@ -2660,7 +2652,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *
         */
         if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
             table->query_id != thd->query_id && /* skip tables already used */
-            !(thd->prelocked_mode && table->query_id) &&
+            (thd->locked_tables_mode == LTM_LOCK_TABLES ||
+             table->query_id == 0) &&
             !table->parent)
         {
           int distance= ((int) table->reginfo.lock_type -
@@ -2743,7 +2736,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
       so we may only end up here if the table did not exist when
       locked tables list was created.
     */
-    if (thd->prelocked_mode == PRELOCKED)
+    if (thd->locked_tables_mode == LTM_PRELOCKED)
       my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
     else
       my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
@@ -3271,7 +3264,7 @@ void close_data_files_and_leave_as_place
 
   safe_mutex_assert_owner(&LOCK_open);
 
-  if (thd->lock)
+  if (! thd->locked_tables_mode)
   {
     /*
       If we are not under LOCK TABLES we should have only one table
@@ -3286,7 +3279,7 @@ void close_data_files_and_leave_as_place
     if (!strcmp(table->s->table_name.str, table_name) &&
 	!strcmp(table->s->db.str, db))
     {
-      if (thd->locked_tables)
+      if (thd->locked_tables_mode)
       {
         if (table->parent)
         {
@@ -3296,11 +3289,11 @@ void close_data_files_and_leave_as_place
             the parent and close it. OTOH in most cases a MERGE table
             won't have multiple children with the same db.table_name.
           */
-          mysql_lock_remove(thd, thd->locked_tables, table->parent, TRUE);
+          mysql_lock_remove(thd, thd->lock, table->parent, TRUE);
           close_handle_and_leave_table_as_placeholder(table->parent);
         }
         else
-          mysql_lock_remove(thd, thd->locked_tables, table, TRUE);
+          mysql_lock_remove(thd, thd->lock, table, TRUE);
       }
       table->s->version= 0;
       close_handle_and_leave_table_as_placeholder(table);
@@ -3496,7 +3489,7 @@ bool reopen_tables(THD *thd, bool get_lo
     if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables),
                                  flags, &not_used)))
     {
-      thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
+      thd->lock= mysql_lock_merge(thd->lock, lock);
     }
     else
     {
@@ -3529,17 +3522,22 @@ void unlock_locked_tables(THD *thd)
   DBUG_ASSERT(!thd->in_sub_stmt &&
               !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
 
-  if (thd->locked_tables)
-  {
-    thd->lock= thd->locked_tables;
-    thd->locked_tables=0;
-    close_thread_tables(thd);
-    /*
-      After closing tables we can free memory used for storing lock
-      request objects for metadata locks
-     */
-    free_root(&thd->locked_tables_root, MYF(MY_MARK_BLOCKS_FREE));
-  }
+  /*
+    Sic: we must be careful to not close open tables if
+    we're not in LOCK TABLES mode: unlock_locked_tables() is
+    sometimes called implicitly, expecting no effect on
+    open tables, e.g. from begin_trans().
+  */
+  if (thd->locked_tables_mode != LTM_LOCK_TABLES)
+    return;
+
+  thd->locked_tables_mode= LTM_NONE;
+  close_thread_tables(thd);
+  /*
+    After closing tables we can free memory used for storing lock
+    request objects for metadata locks
+  */
+  free_root(&thd->locked_tables_root, MYF(MY_MARK_BLOCKS_FREE));
 }
 
 
@@ -4387,11 +4385,6 @@ bool fix_merge_after_open(TABLE_LIST *ol
     prelocking it won't do such precaching and will simply reuse table list
     which is already built.
 
-    If any table has a trigger and start->trg_event_map is non-zero
-    the final lock will end up in thd->locked_tables, otherwise, the
-    lock will be placed in thd->lock. See also comments in
-    st_lex::set_trg_event_type_for_tables().
-
   RETURN
     0  - OK
     -1 - error
@@ -4436,10 +4429,10 @@ int open_tables(THD *thd, TABLE_LIST **s
     If we are not already executing prelocked statement and don't have
     statement for which table list for prelocking is already built, let
     us cache routines and try to build such table list.
-
   */
 
-  if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+  if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+      !thd->lex->requires_prelocking() &&
       thd->lex->uses_stored_routines())
   {
     bool first_no_prelocking, need_prelocking;
@@ -4653,7 +4646,8 @@ int open_tables(THD *thd, TABLE_LIST **s
         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->prelocked_mode && !thd->lex->requires_prelocking() &&
+      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)
       {
@@ -4674,7 +4668,7 @@ int open_tables(THD *thd, TABLE_LIST **s
       free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
     }
 
-    if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
+    if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
     {
       if (tables->lock_type == TL_WRITE_DEFAULT)
         tables->table->reginfo.lock_type= thd->update_lock_default;
@@ -4694,10 +4688,7 @@ int open_tables(THD *thd, TABLE_LIST **s
     DBUG_PRINT("tcache", ("is parent: %d  is child: %d",
                           test(tables->table->child_l),
                           test(tables->parent_l)));
-    DBUG_PRINT("tcache", ("in lock tables: %d  in prelock mode: %d",
-                          test(thd->locked_tables), test(thd->prelocked_mode)));
-    if (((!thd->locked_tables && !thd->prelocked_mode) ||
-         tables->table->s->tmp_table) &&
+    if ((!thd->locked_tables_mode || tables->table->s->tmp_table) &&
         ((tables->table->child_l &&
           add_merge_table_list(tables)) ||
          (tables->parent_l &&
@@ -4713,7 +4704,8 @@ process_view_routines:
       Again we may need cache all routines used by this view and add
       tables used by them to table list.
     */
-    if (tables->view && !thd->prelocked_mode &&
+    if (tables->view &&
+        thd->locked_tables_mode <= LTM_LOCK_TABLES &&
         !thd->lex->requires_prelocking() &&
         tables->view->uses_stored_routines())
     {
@@ -4921,7 +4913,7 @@ retry:
     table_list->lock_type= lock_type;
     table_list->table=	   table;
     table->grant= table_list->grant;
-    if (thd->locked_tables)
+    if (thd->locked_tables_mode)
     {
       if (check_lock_and_start_stmt(thd, table, lock_type))
 	table= 0;
@@ -5223,9 +5215,9 @@ int decide_logging_format(THD *thd, TABL
     handling thr_lock gives us.  You most always get all needed locks at
     once.
 
-    If query for which we are calling this function marked as requring
-    prelocking, this function will do implicit LOCK TABLES and change
-    thd::prelocked_mode accordingly.
+    If query for which we are calling this function marked as requiring
+    prelocking, this function will change locked_tables_mode to
+    LTM_PRELOCKED.
 
   RETURN VALUES
    0	ok
@@ -5242,22 +5234,24 @@ int lock_tables(THD *thd, TABLE_LIST *ta
     We can't meet statement requiring prelocking if we already
     in prelocked mode.
   */
-  DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
+  DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
+              !thd->lex->requires_prelocking());
   *need_reopen= FALSE;
 
   if (!tables && !thd->lex->requires_prelocking())
     DBUG_RETURN(decide_logging_format(thd, tables));
 
   /*
-    We need this extra check for thd->prelocked_mode because we want to avoid
-    attempts to lock tables in substatements. Checking for thd->locked_tables
-    is not enough in some situations. For example for SP containing
+    Check for thd->locked_tables_mode to avoid a redundant
+    and harmful attempt to lock the already locked tables again.
+    Checking for thd->lock is not enough in some situations. For example,
+    if a stored function contains
     "drop table t3; create temporary t3 ..; insert into t3 ...;"
-    thd->locked_tables may be 0 after drop tables, and without this extra
-    check insert will try to lock temporary table t3, that will lead
-    to memory leak...
+    thd->lock may be 0 after drop tables, whereas locked_tables_mode
+    is still on. In this situation an attempt to lock temporary
+    table t3 will lead to a memory leak.
   */
-  if (!thd->locked_tables && !thd->prelocked_mode)
+  if (! thd->locked_tables_mode)
   {
     DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
     TABLE **start,**ptr;
@@ -5307,15 +5301,8 @@ int lock_tables(THD *thd, TABLE_LIST *ta
         We just have done implicit LOCK TABLES, and now we have
         to emulate first open_and_lock_tables() after it.
 
-        Note that "LOCK TABLES" can also be marked as requiring prelocking
-        (e.g. if one locks view which uses functions). We should not emulate
-        such open_and_lock_tables() in this case. We also should not set
-        THD::prelocked_mode or first close_thread_tables() call will do
-        "UNLOCK TABLES".
       */
-      thd->locked_tables= thd->lock;
-      thd->lock= 0;
-      thd->in_lock_tables=0;
+      thd->in_lock_tables= 0;
 
       /*
         When open_and_lock_tables() is called for a single table out of
@@ -5338,8 +5325,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
               This was an attempt to enter prelocked mode so there is no
               need to care about THD::locked_tables_root here.
             */
-            mysql_unlock_tables(thd, thd->locked_tables);
-            thd->locked_tables= 0;
+            mysql_unlock_tables(thd, thd->lock);
             thd->options&= ~(OPTION_TABLE_LOCK);
             DBUG_RETURN(-1);
           }
@@ -5351,7 +5337,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
       */
       mark_real_tables_as_free_for_reuse(first_not_own);
       DBUG_PRINT("info",("prelocked_mode= PRELOCKED"));
-      thd->prelocked_mode= PRELOCKED;
+      thd->locked_tables_mode= LTM_PRELOCKED;
     }
   }
   else
@@ -5384,7 +5370,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
     {
       mark_real_tables_as_free_for_reuse(first_not_own);
       DBUG_PRINT("info", ("thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES"));
-      thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
+      thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES;
     }
   }
 

=== modified file 'sql/sql_cache.cc'
--- a/sql/sql_cache.cc	2008-05-08 16:01:15 +0000
+++ b/sql/sql_cache.cc	2008-06-06 19:17:47 +0000
@@ -993,7 +993,7 @@ void Query_cache::store_query(THD *thd, 
 
     See also a note on double-check locking usage above.
   */
-  if (thd->locked_tables || query_cache_size == 0)
+  if (thd->locked_tables_mode || query_cache_size == 0)
     DBUG_VOID_RETURN;
   uint8 tables_type= 0;
 
@@ -1205,7 +1205,7 @@ Query_cache::send_result_to_client(THD *
 
     See also a note on double-check locking usage above.
   */
-  if (thd->locked_tables || thd->variables.query_cache_type == 0 ||
+  if (thd->locked_tables_mode || thd->variables.query_cache_type == 0 ||
       query_cache_size == 0)
     goto err;
 

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-05-23 13:54:03 +0000
+++ b/sql/sql_class.cc	2008-06-06 19:17:47 +0000
@@ -846,11 +846,7 @@ void THD::cleanup(void)
     ha_rollback(this);
     xid_cache_delete(&transaction.xid_state);
   }
-  if (locked_tables)
-  {
-    lock=locked_tables; locked_tables=0;
-    close_thread_tables(this);
-  }
+  unlock_locked_tables(this);
   mysql_ha_cleanup(this);
   delete_dynamic(&user_var_events);
   hash_free(&user_vars);
@@ -1645,7 +1641,7 @@ bool select_send::send_eof()
   ha_release_temporary_latches(thd);
 
   /* Unlock tables before sending packet to gain some speed */
-  if (thd->lock)
+  if (thd->lock && ! thd->locked_tables_mode)
   {
     mysql_unlock_tables(thd, thd->lock);
     thd->lock=0;
@@ -2853,8 +2849,8 @@ void THD::restore_backup_open_tables_sta
   */
   DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
               handler_tables == 0 && derived_tables == 0 &&
-              lock == 0 && locked_tables == 0 &&
-              prelocked_mode == NON_PRELOCKED &&
+              lock == 0 &&
+              locked_tables_mode == LTM_NONE &&
               m_reprepare_observer == NULL);
   mdl_context_destroy(&mdl_context);
   mdl_context_destroy(&handler_mdl_context);
@@ -3637,7 +3633,7 @@ int THD::binlog_query(THD::enum_binlog_q
     If we are in prelocked mode, the flushing will be done inside the
     top-most close_thread_tables().
   */
-  if (this->prelocked_mode == NON_PRELOCKED)
+  if (this->locked_tables_mode <= LTM_LOCK_TABLES)
     if (int error= binlog_flush_pending_rows_event(TRUE))
       DBUG_RETURN(error);
 

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-05-23 13:54:03 +0000
+++ b/sql/sql_class.h	2008-06-06 19:17:47 +0000
@@ -873,12 +873,17 @@ typedef I_List<Item_change_record> Item_
 
 
 /**
-  Type of prelocked mode.
-  See comment for THD::prelocked_mode for complete description.
+  Type of locked tables mode.
+  See comment for THD::locked_tables_mode for complete description.
 */
 
-enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
-                          PRELOCKED_UNDER_LOCK_TABLES= 2};
+enum enum_locked_tables_mode
+{
+  LTM_NONE= 0,
+  LTM_LOCK_TABLES,
+  LTM_PRELOCKED,
+  LTM_PRELOCKED_UNDER_LOCK_TABLES
+};
 
 
 /**
@@ -931,19 +936,13 @@ public:
     statement ends.
     Manual mode comes into play when a user issues a 'LOCK TABLES'
     statement. In this mode the user can only use the locked tables.
-    Trying to use any other tables will give an error. The locked tables are
-    stored in 'locked_tables' member.  Manual locking is described in
+    Trying to use any other tables will give an error.
+    The locked tables are also stored in this member, however,
+    thd->locked_tables_mode is turned on.  Manual locking is described in
     the 'LOCK_TABLES' chapter of the MySQL manual.
     See also lock_tables() for details.
   */
   MYSQL_LOCK *lock;
-  /*
-    Tables that were locked with explicit or implicit LOCK TABLES.
-    (Implicit LOCK TABLES happens when we are prelocking tables for
-     execution of statement which uses stored routines. See description
-     THD::prelocked_mode for more info.)
-  */
-  MYSQL_LOCK *locked_tables;
 
   /*
     CREATE-SELECT keeps an extra lock for the table being
@@ -953,29 +952,34 @@ public:
   MYSQL_LOCK *extra_lock;
 
   /*
-    prelocked_mode_type enum and prelocked_mode member are used for
-    indicating whenever "prelocked mode" is on, and what type of
-    "prelocked mode" is it.
-
-    Prelocked mode is used for execution of queries which explicitly
-    or implicitly (via views or triggers) use functions, thus may need
-    some additional tables (mentioned in query table list) for their
-    execution.
-
-    First open_tables() call for such query will analyse all functions
-    used by it and add all additional tables to table its list. It will
-    also mark this query as requiring prelocking. After that lock_tables()
-    will issue implicit LOCK TABLES for the whole table list and change
-    thd::prelocked_mode to non-0. All queries called in functions invoked
-    by the main query will use prelocked tables. Non-0 prelocked_mode
-    will also surpress mentioned analysys in those queries thus saving
-    cycles. Prelocked mode will be turned off once close_thread_tables()
-    for the main query will be called.
-
-    Note: Since not all "tables" present in table list are really locked
-    thd::prelocked_mode does not imply thd::locked_tables.
+    Enum enum_locked_tables_mode and locked_tables_mode member are
+    used to indicate whether the so-called "locked tables mode" is on,
+    and what kind of mode is active.
+
+    Locked tables mode is used when it's necessary to open and
+    lock many tables at once, for usage across multiple
+    (sub-)statements.
+    This may be necessary either for queries that use stored functions
+    and triggers, in which case the statements inside functions and
+    triggers may be executed many times, or for implementation of
+    LOCK TABLES, in which case the opened tables are reused by all
+    subsequent statements until a call to UNLOCK TABLES.
+
+    The kind of locked tables mode employed for stored functions and
+    triggers is also called "prelocked mode".
+    In this mode, first open_tables() call to open the tables used
+    in a statement analyses all functions used by the statement
+    and adds all indirectly used tables to the list of tables to
+    open and lock.
+    It also marks the parse tree of the statement as requiring
+    prelocking. After that, lock_tables() locks the entire list
+    of tables and changes THD::locked_tables_modeto LTM_PRELOCKED.
+    All statements executed inside functions or triggers
+    use the prelocked tables, instead of opening their own ones.
+    Prelocked mode is turned off automatically once close_thread_tables()
+    of the main statement is called.
   */
-  prelocked_mode_type prelocked_mode;
+  enum enum_locked_tables_mode locked_tables_mode;
   ulong	version;
   uint current_tablenr;
 
@@ -1007,8 +1011,8 @@ public:
   void reset_open_tables_state(THD *thd)
   {
     open_tables= temporary_tables= handler_tables= derived_tables= 0;
-    extra_lock= lock= locked_tables= 0;
-    prelocked_mode= NON_PRELOCKED;
+    extra_lock= lock= 0;
+    locked_tables_mode= LTM_NONE;
     state_flags= 0U;
     m_reprepare_observer= NULL;
     mdl_context_init(&mdl_context, thd);

=== modified file 'sql/sql_cursor.cc'
--- a/sql/sql_cursor.cc	2008-05-21 10:17:29 +0000
+++ b/sql/sql_cursor.cc	2008-06-06 19:17:47 +0000
@@ -275,7 +275,6 @@ Sensitive_cursor::Sensitive_cursor(THD *
   Save THD state into cursor.
 
   @todo
-    - XXX: thd->locked_tables is not changed.
     -  What problems can we have with it if cursor is open?
     - TODO: must be fixed because of the prelocked mode.
 */
@@ -328,7 +327,6 @@ Sensitive_cursor::post_open(THD *thd)
     }
   }
   /*
-    XXX: thd->locked_tables is not changed.
     What problems can we have with it if cursor is open?
     TODO: must be fixed because of the prelocked mode.
   */

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2008-06-04 12:27:06 +0000
+++ b/sql/sql_insert.cc	2008-06-06 19:17:47 +0000
@@ -427,7 +427,7 @@ void upgrade_lock_type(THD *thd, thr_loc
     */
     if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
         thd->variables.max_insert_delayed_threads == 0 ||
-        thd->prelocked_mode ||
+        thd->locked_tables_mode > LTM_LOCK_TABLES ||
         thd->lex->uses_stored_routines())
     {
       *lock_type= TL_WRITE;
@@ -597,7 +597,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
     never be able to get a lock on the table. QQQ: why not
     upgrade the lock here instead?
   */
-  if (table_list->lock_type == TL_WRITE_DELAYED && thd->locked_tables &&
+  if (table_list->lock_type == TL_WRITE_DELAYED &&
+      thd->locked_tables_mode &&
       find_locked_table(thd->open_tables, table_list->db,
                         table_list->table_name))
   {
@@ -732,7 +733,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   {
     if (duplic != DUP_ERROR || ignore)
       table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
-    if (!thd->prelocked_mode)
+    /**
+      This is a simple check for the case when the table has a trigger
+      that reads from it, or when the statement invokes a stored function
+      that reads from the table being inserted to.
+      Engines can't handle a bulk insert in parallel with a read form the
+      same table in the same connection.
+    */
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
       table->file->ha_start_bulk_insert(values_list.elements);
   }
 
@@ -848,7 +856,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       auto_inc values from the delayed_insert thread as they share TABLE.
     */
     table->file->ha_release_auto_increment();
-    if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+        table->file->ha_end_bulk_insert() && !error)
     {
       table->file->print_error(my_errno,MYF(0));
       error=1;
@@ -2989,7 +2998,7 @@ select_insert::prepare(List<Item> &value
     lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
   }
   else if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
-           !thd->prelocked_mode)
+           thd->locked_tables_mode <= LTM_LOCK_TABLES)
   {
     /*
       We must not yet prepare the result table if it is the same as one of the 
@@ -3055,7 +3064,7 @@ int select_insert::prepare2(void)
 {
   DBUG_ENTER("select_insert::prepare2");
   if (thd->lex->current_select->options & OPTION_BUFFER_RESULT &&
-      !thd->prelocked_mode)
+      thd->locked_tables_mode <= LTM_LOCK_TABLES)
     table->file->ha_start_bulk_insert((ha_rows) 0);
   DBUG_RETURN(0);
 }
@@ -3175,7 +3184,8 @@ bool select_insert::send_eof()
   DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
                        trans_table, table->file->table_type()));
 
-  error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
+  error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
+          table->file->ha_end_bulk_insert() : 0);
   table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
   table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
 
@@ -3249,7 +3259,7 @@ void select_insert::abort() {
       If we are not in prelocked mode, we end the bulk insert started
       before.
     */
-    if (!thd->prelocked_mode)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
       table->file->ha_end_bulk_insert();
 
     /*
@@ -3619,7 +3629,7 @@ select_create::prepare(List<Item> &value
     table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
   if (info.handle_duplicates == DUP_UPDATE)
     table->file->extra(HA_EXTRA_INSERT_WITH_UPDATE);
-  if (!thd->prelocked_mode)
+  if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
     table->file->ha_start_bulk_insert((ha_rows) 0);
   thd->abort_on_warning= (!info.ignore &&
                           (thd->variables.sql_mode &

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2008-04-14 10:15:04 +0000
+++ b/sql/sql_load.cc	2008-06-06 19:17:47 +0000
@@ -408,7 +408,7 @@ int mysql_load(THD *thd,sql_exchange *ex
         (!table->triggers ||
          !table->triggers->has_delete_triggers()))
         table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
-    if (!thd->prelocked_mode)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
       table->file->ha_start_bulk_insert((ha_rows) 0);
     table->copy_blobs=1;
 
@@ -429,7 +429,8 @@ int mysql_load(THD *thd,sql_exchange *ex
       error= read_sep_field(thd, info, table_list, fields_vars,
                             set_fields, set_values, read_info,
 			    *enclosed, skip_lines, ignore);
-    if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+    if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+        table->file->ha_end_bulk_insert() && !error)
     {
       table->file->print_error(my_errno, MYF(0));
       error= 1;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-06-04 12:27:06 +0000
+++ b/sql/sql_parse.cc	2008-06-06 19:17:47 +0000
@@ -115,7 +115,7 @@ bool end_active_trans(THD *thd)
   {
     DBUG_PRINT("info",("options: 0x%llx", thd->options));
     /* Safety if one did "drop table" on locked tables */
-    if (!thd->locked_tables)
+    if (!thd->locked_tables_mode)
       thd->options&= ~OPTION_TABLE_LOCK;
     thd->server_status&= ~SERVER_STATUS_IN_TRANS;
     if (ha_commit(thd))
@@ -1202,7 +1202,7 @@ bool dispatch_command(enum enum_server_c
       }
       if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
 	break;
-      if (thd->locked_tables || thd->active_transaction())
+      if (thd->locked_tables_mode || thd->active_transaction())
       {
 	my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                    ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -2324,7 +2324,7 @@ mysql_execute_command(THD *thd)
       created during a gobal read lock.
     */
     DDL_blocker->check_DDL_blocker(thd);
-    if (!thd->locked_tables &&
+    if (!thd->locked_tables_mode &&
         !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
     {
       res= 1;
@@ -2517,7 +2517,8 @@ end_with_restore_list:
     To prevent that, refuse SLAVE STOP if the
     client thread has locked tables
   */
-  if (thd->locked_tables || thd->active_transaction() || thd->global_read_lock)
+  if (thd->locked_tables_mode ||
+      thd->active_transaction() || thd->global_read_lock)
   {
     my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -2601,7 +2602,7 @@ end_with_restore_list:
       if (end_active_trans(thd))
 	goto error;
 
-      if (!thd->locked_tables &&
+      if (!thd->locked_tables_mode &&
           !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
       {
         res= 1;
@@ -2926,7 +2927,7 @@ end_with_restore_list:
     if ((res= insert_precheck(thd, all_tables)))
       break;
 
-    if (!thd->locked_tables &&
+    if (!thd->locked_tables_mode &&
         !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
     {
       res= 1;
@@ -2966,7 +2967,7 @@ end_with_restore_list:
 
     unit->set_limit(select_lex);
 
-    if (! thd->locked_tables &&
+    if (! thd->locked_tables_mode &&
         ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
     {
       res= 1;
@@ -3036,7 +3037,7 @@ end_with_restore_list:
       Don't allow this within a transaction because we want to use
       re-generate table
     */
-    if (thd->locked_tables || thd->active_transaction())
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                  ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -3056,7 +3057,7 @@ end_with_restore_list:
     DBUG_ASSERT(select_lex->offset_limit == 0);
     unit->set_limit(select_lex);
 
-    if (!thd->locked_tables &&
+    if (!thd->locked_tables_mode &&
         !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
     {
       res= 1;
@@ -3076,7 +3077,7 @@ end_with_restore_list:
       (TABLE_LIST *)thd->lex->auxiliary_table_list.first;
     multi_delete *del_result;
 
-    if (!thd->locked_tables &&
+    if (!thd->locked_tables_mode &&
         !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
     {
       res= 1;
@@ -3289,13 +3290,13 @@ end_with_restore_list:
     /*
       We try to take transactional locks if
       - only transactional locks are requested (lex->lock_transactional) and
-      - no non-transactional locks exist (!thd->locked_tables).
+      - no non-transactional locks exist (!thd->locked_tables_mode).
     */
     DBUG_PRINT("lock_info", ("lex->lock_transactional: %d  "
-                             "thd->locked_tables: %p",
+                             "thd->lock: %p",
                              lex->lock_transactional,
-                             thd->locked_tables));
-    if (lex->lock_transactional && !thd->locked_tables)
+                             thd->lock));
+    if (lex->lock_transactional && !thd->locked_tables_mode)
     {
       int rc;
       /*
@@ -3341,11 +3342,8 @@ end_with_restore_list:
       if (thd->variables.query_cache_wlock_invalidate)
 	query_cache.invalidate_locked_for_write(first_table);
 #endif /*HAVE_QUERY_CACHE*/
-      thd->locked_tables=thd->lock;
-      thd->lock=0;
+      thd->locked_tables_mode= LTM_LOCK_TABLES;
       (void) set_handler_table_locks(thd, all_tables, FALSE);
-      DBUG_PRINT("lock_info", ("thd->locked_tables: %p",
-                               thd->locked_tables));
       my_ok(thd);
     }
     else
@@ -3438,7 +3436,7 @@ end_with_restore_list:
     if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
                      is_schema_db(lex->name.str)))
       break;
-    if (thd->locked_tables || thd->active_transaction())
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                  ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -3479,7 +3477,7 @@ end_with_restore_list:
       res= 1;
       break;
     }
-    if (thd->locked_tables || thd->active_transaction())
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       res= 1;
       my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
@@ -3521,7 +3519,7 @@ end_with_restore_list:
 #endif
     if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
       break;
-    if (thd->locked_tables || thd->active_transaction())
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                  ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -4480,7 +4478,7 @@ create_sp_error:
                xa_state_names[thd->transaction.xid_state.xa_state]);
       break;
     }
-    if (thd->active_transaction() || thd->locked_tables)
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       my_error(ER_XAER_OUTSIDE, MYF(0));
       break;
@@ -6676,7 +6674,7 @@ bool reload_acl_and_cache(THD *thd, ulon
         if we have a write locked table as this would lead to a deadlock
         when trying to reopen (and re-lock) the table after the flush.
       */
-      if (thd->locked_tables)
+      if (thd->locked_tables_mode)
       {
         my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
         return 1;
@@ -6699,7 +6697,7 @@ bool reload_acl_and_cache(THD *thd, ulon
     }
     else
     {
-      if (thd && thd->locked_tables)
+      if (thd && thd->locked_tables_mode)
       {
         /*
           If we are under LOCK TABLES we should have a write

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2008-06-05 06:48:36 +0000
+++ b/sql/sql_partition.cc	2008-06-06 19:17:47 +0000
@@ -5782,7 +5782,7 @@ static void release_log_entries(partitio
 static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
 {
   int err;
-  if (lpt->thd->locked_tables)
+  if (lpt->thd->locked_tables_mode)
   {
     /*
       When we have the table locked, it is necessary to reopen the table

=== modified file 'sql/sql_rename.cc'
--- a/sql/sql_rename.cc	2008-05-23 13:54:03 +0000
+++ b/sql/sql_rename.cc	2008-06-06 19:17:47 +0000
@@ -44,7 +44,7 @@ bool mysql_rename_tables(THD *thd, TABLE
     if the user is trying to to do this in a transcation context
   */
 
-  if (thd->locked_tables || thd->active_transaction())
+  if (thd->locked_tables_mode || thd->active_transaction())
   {
     my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-05-16 16:30:05 +0000
+++ b/sql/sql_select.cc	2008-06-06 19:17:47 +0000
@@ -1523,7 +1523,7 @@ JOIN::optimize()
     error= -1;
     DBUG_RETURN(1);
   }
-  if (const_tables && !thd->locked_tables &&
+  if (const_tables && !thd->locked_tables_mode &&
       !(select_options & SELECT_NO_UNLOCK))
     mysql_unlock_some_tables(thd, table, const_tables);
   if (!conds && outer_join)
@@ -8492,7 +8492,7 @@ void JOIN::join_free()
     We are not using tables anymore
     Unlock all tables. We may be in an INSERT .... SELECT statement.
   */
-  if (can_unlock && lock && thd->lock &&
+  if (can_unlock && lock && thd->lock && ! thd->locked_tables_mode &&
       !(select_options & SELECT_NO_UNLOCK) &&
       !select_lex->subquery_in_having &&
       (select_lex == (thd->lex->unit.fake_select_lex ?

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-06-05 15:33:38 +0000
+++ b/sql/sql_table.cc	2008-06-06 19:17:47 +0000
@@ -1481,7 +1481,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST 
 
   if (!drop_temporary)
   {
-    if (!thd->locked_tables &&
+    if (!thd->locked_tables_mode &&
         !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
       DBUG_RETURN(TRUE);
   }
@@ -1582,7 +1582,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
 
   if (!drop_temporary)
   {
-    if (!thd->locked_tables)
+    if (!thd->locked_tables_mode)
     {
       if (lock_table_names(thd, tables))
         DBUG_RETURN(1);
@@ -1591,7 +1591,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
         expel_table_from_cache(0, table->db, table->table_name);
       pthread_mutex_unlock(&LOCK_open);
     }
-    else if (thd->locked_tables)
+    else
     {
       for (table= tables; table; table= table->next_local)
         if (find_temporary_table(thd, table->db, table->table_name))
@@ -1676,7 +1676,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
     table_type= table->db_type;
     if (!drop_temporary)
     {
-      if (thd->locked_tables)
+      if (thd->locked_tables_mode)
       {
         if (close_cached_table(thd, table->table))
         {
@@ -1837,8 +1837,8 @@ err_with_placeholders:
       locked. Additional check for 'non_temp_tables_count' is to avoid
       leaving LOCK TABLES mode if we have dropped only temporary tables.
     */
-    if (thd->locked_tables && thd->locked_tables->table_count == 0 &&
-        non_temp_tables_count > 0)
+    if (thd->locked_tables_mode &&
+        thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
     {
       unlock_locked_tables(thd);
       goto end;
@@ -6364,7 +6364,7 @@ bool mysql_alter_table(THD *thd,char *ne
       if the user is trying to to do this in a transcation context
     */
 
-    if (thd->locked_tables || thd->active_transaction())
+    if (thd->locked_tables_mode || thd->active_transaction())
     {
       my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
                  ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
@@ -6412,7 +6412,7 @@ view_err:
     set of tables from the old table or to open a new TABLE object for
     an extended list and verify that they belong to locked tables.
   */
-  if (thd->locked_tables &&
+  if (thd->locked_tables_mode &&
       (create_info->used_fields & HA_CREATE_USED_UNION) &&
       (table->s->tmp_table == NO_TMP_TABLE))
   {
@@ -6626,7 +6626,7 @@ view_err:
     table_list->table= NULL;                    // For query cache
     query_cache_invalidate3(thd, table_list, 0);
 
-    if (thd->locked_tables)
+    if (thd->locked_tables_mode)
     {
       /*
         Under LOCK TABLES we should adjust meta-data locks before finishing
@@ -6809,7 +6809,7 @@ view_err:
                                               &ha_alter_info,
                                               &ha_alter_flags,
                                               alter_info->keys_onoff);
-      if (thd->lock)
+      if (thd->lock && !thd->locked_tables_mode)
       {
         mysql_unlock_tables(thd, thd->lock);
         thd->lock=0;
@@ -6913,7 +6913,7 @@ view_err:
   if (table->s->tmp_table != NO_TMP_TABLE)
   {
     /* Close lock if this is a transactional table */
-    if (thd->lock)
+    if (thd->lock && ! thd->locked_tables_mode)
     {
       mysql_unlock_tables(thd, thd->lock);
       thd->lock=0;
@@ -7012,7 +7012,7 @@ view_err:
   (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
 
 end_online:
-  if (thd->locked_tables && new_name == table_name && new_db == db)
+  if (thd->locked_tables_mode && new_name == table_name && new_db == db)
   {
     thd->in_lock_tables= 1;
     error= reopen_tables(thd, 1);
@@ -7059,7 +7059,7 @@ end_online:
   table_list->table=0;				// For query cache
   query_cache_invalidate3(thd, table_list, 0);
 
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     if ((new_name != table_name || new_db != db))
     {

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2008-06-05 06:48:36 +0000
+++ b/sql/sql_trigger.cc	2008-06-06 19:17:47 +0000
@@ -383,7 +383,7 @@ bool mysql_create_or_drop_trigger(THD *t
     LOCK_open is not enough because global read lock is held without holding
     LOCK_open).
   */
-  if (!thd->locked_tables &&
+  if (!thd->locked_tables_mode &&
       !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
     DBUG_RETURN(TRUE);
 
@@ -444,7 +444,7 @@ bool mysql_create_or_drop_trigger(THD *t
   /* Keep consistent with respect to other DDL statements */
   mysql_ha_rm_tables(thd, tables);
 
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     /* Under LOCK TABLES we must only accept write locked tables. */
     if (!(tables->table= find_write_locked_table(thd->open_tables, tables->db,
@@ -493,7 +493,7 @@ bool mysql_create_or_drop_trigger(THD *t
            table->triggers->drop_trigger(thd, tables, &stmt_query));
 
   /* Under LOCK TABLES we must reopen the table to activate the trigger. */
-  if (!result && thd->locked_tables)
+  if (!result && thd->locked_tables_mode)
   {
     /* Make table suitable for reopening */
     close_data_files_and_leave_as_placeholders(thd, tables->db,
@@ -527,7 +527,7 @@ end:
     locks. Otherwise call to close_thread_tables() will take care about both
     TABLE instance created by reopen_name_locked_table() and metadata lock.
   */
-  if (thd->locked_tables && tables && tables->table)
+  if (thd->locked_tables_mode && tables && tables->table)
     mdl_downgrade_exclusive_lock(&thd->mdl_context,
                                  tables->table->mdl_lock_data);
 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2008-05-27 17:31:53 +0000
+++ b/sql/sql_update.cc	2008-06-06 19:17:47 +0000
@@ -962,7 +962,7 @@ int mysql_multi_update_prepare(THD *thd)
     count in open_tables()
   */
   uint  table_count= lex->table_count;
-  const bool using_lock_tables= thd->locked_tables != 0;
+  const bool using_lock_tables= thd->locked_tables_mode != LTM_NONE;
   bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
   bool need_reopen= FALSE;
   DBUG_ENTER("mysql_multi_update_prepare");

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2008-06-04 12:27:06 +0000
+++ b/sql/sql_view.cc	2008-06-06 19:17:47 +0000
@@ -383,7 +383,7 @@ bool mysql_create_view(THD *thd, TABLE_L
     alteration of views under LOCK TABLES.
   */
 
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
     res= TRUE;
@@ -1573,7 +1573,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIS
     TABLES we have to simply prohibit dropping of views.
   */
 
-  if (thd->locked_tables)
+  if (thd->locked_tables_mode)
   {
     my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
     DBUG_RETURN(TRUE);

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2008-05-27 12:15:44 +0000
+++ b/storage/myisam/ha_myisam.cc	2008-06-06 19:17:47 +0000
@@ -942,7 +942,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK
   strmov(fixed_name,file->filename);
 
   // Don't lock tables if we have used LOCK TABLE
-  if (!thd->locked_tables && 
+  if (! thd->locked_tables_mode &&
       mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
   {
     mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
@@ -1052,7 +1052,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK
     update_state_info(&param, file, 0);
   }
   thd_proc_info(thd, old_proc_info);
-  if (!thd->locked_tables)
+  if (! thd->locked_tables_mode)
     mi_lock_database(file,F_UNLCK);
   DBUG_RETURN(error ? HA_ADMIN_FAILED :
 	      !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);

Thread
bzr commit into mysql-6.0 branch (konstantin:2662) WL#3726Konstantin Osipov6 Jun