List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:April 7 2012 11:18pm
Subject:bzr push into mysql-trunk branch (mattias.jonsson:3875 to 3876) WL#4443
View as plain text  
 3876 Mattias Jonsson	2012-04-08
      WL#4443 - Prune partition locks.
      Updated with dlenev's review patch chunk 1.

    modified:
      sql/opt_explain.cc
      sql/rpl_info_table_access.cc
      sql/sp_head.cc
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_delete.cc
      sql/sql_insert.cc
      sql/sql_lex.cc
      sql/sql_lex.h
      sql/sql_load.cc
      sql/sql_parse.cc
      sql/sql_parse.h
      sql/sql_prepare.cc
      sql/sql_select.cc
      sql/sql_union.cc
      sql/sql_update.cc
      sql/sql_view.cc
 3875 Mattias Jonsson	2012-03-30
      WL#4443:
      Updated some result files.
      removed debug runs from push.
      added fix for preventing stored functions to execute during prepare
      (to avoid using tables before open/lock).

    modified:
      mysql-test/collections/mysql-trunk-wl4443.push
      mysql-test/r/innodb_explain_json_non_select_all.result
      mysql-test/r/innodb_explain_json_non_select_none.result
      mysql-test/r/myisam_explain_json_non_select_all.result
      mysql-test/r/myisam_explain_json_non_select_none.result
      mysql-test/suite/rpl/r/rpl_parallel_change_master.result
      mysql-test/t/partition_locking.test
      sql/item.cc
=== modified file 'sql/opt_explain.cc'
--- a/sql/opt_explain.cc	revid:mattias.jonsson@stripped
+++ b/sql/opt_explain.cc	revid:mattias.jonsson@stripped
@@ -21,7 +21,7 @@
 #include "sql_partition.h" // for make_used_partitions_str()
 #include "sql_join_buffer.h" // JOIN_CACHE
 #include "opt_explain_format.h"
-#include "sql_base.h"      // open_query_tables, lock_query_tables
+#include "sql_base.h"      // lock_tables
 
 typedef qep_row::extra extra;
 
@@ -1963,17 +1963,23 @@ bool mysql_explain_unit(THD *thd, SELECT
     unit->fake_select_lex->select_number= UINT_MAX; // just for initialization
     unit->fake_select_lex->options|= SELECT_DESCRIBE;
 
-    if (open_query_tables(thd))
-      DBUG_RETURN(true);
-
     res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE);
 
     if (res)
       DBUG_RETURN(res);
 
-    if (lock_query_tables(thd))
+    /*
+      If tables are not locked at this point, it means that we have delayed
+      this step until after prepare stage (now), in order to do better
+      partition pruning.
+
+      We need to lock tables now in order to proceed with the remaning
+      stages of query optimization.
+    */
+    if (! thd->lex->is_query_tables_locked() &&
+        lock_tables(thd, thd->lex->query_tables, thd->lex->table_count, 0))
       DBUG_RETURN(true);
-    
+
     res= unit->optimize();
 
     if (!res)

=== modified file 'sql/rpl_info_table_access.cc'
--- a/sql/rpl_info_table_access.cc	revid:mattias.jonsson@stripped
+++ b/sql/rpl_info_table_access.cc	revid:mattias.jonsson@stripped
@@ -52,6 +52,7 @@ bool Rpl_info_table_access::open_table(T
                                        Open_tables_backup* backup)
 {
   TABLE_LIST tables;
+  Query_tables_list query_tables_list_backup;
 
   uint flags= (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
                MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
@@ -71,6 +72,15 @@ bool Rpl_info_table_access::open_table(T
     mysql_reset_thd_for_next_command(thd);
   }
 
+  /*
+    We need to use new Open_tables_state in order not to be affected
+    by LOCK TABLES/prelocked mode.
+    Also in order not to break execution of current statement we also
+    have to backup/reset/restore Query_tables_list part of LEX, which
+    is accessed and updated in the process of opening and locking
+    tables.
+  */
+  thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
   thd->reset_n_backup_open_tables_state(backup);
 
   tables.init_one_table(dbstr.str, dbstr.length, tbstr.str, tbstr.length,
@@ -80,6 +90,7 @@ bool Rpl_info_table_access::open_table(T
   {
     close_thread_tables(thd);
     thd->restore_backup_open_tables_state(backup);
+    thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
     my_error(ER_NO_SUCH_TABLE, MYF(0), dbstr.str, tbstr.str);
     DBUG_RETURN(TRUE);
   }
@@ -95,12 +106,15 @@ bool Rpl_info_table_access::open_table(T
     ha_rollback_trans(thd, FALSE);
     close_thread_tables(thd);
     thd->restore_backup_open_tables_state(backup);
+    thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
     my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, MYF(0),
              tables.table->s->db.str, tables.table->s->table_name.str,
              max_num_field, tables.table->s->fields);
     DBUG_RETURN(TRUE);
   }
 
+  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
+
   *table= tables.table;
   tables.table->use_all_columns();
   DBUG_RETURN(FALSE);
@@ -132,6 +146,8 @@ bool Rpl_info_table_access::close_table(
                                         Open_tables_backup *backup,
                                         bool error)
 {
+  Query_tables_list query_tables_list_backup;
+
   DBUG_ENTER("Rpl_info_table_access::close_table");
 
   if (table)
@@ -148,7 +164,14 @@ bool Rpl_info_table_access::close_table(
       else
         ha_commit_trans(thd, TRUE);
     }
+    /*
+      In order not to break execution of current statement we have to
+      backup/reset/restore Query_tables_list part of LEX, which is
+      accessed and updated in the process of closing tables.
+    */
+    thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
     close_thread_tables(thd);
+    thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
     thd->restore_backup_open_tables_state(backup);
   }
 

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	revid:mattias.jonsson@stripped
+++ b/sql/sp_head.cc	revid:mattias.jonsson@stripped
@@ -2952,7 +2952,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
                                UINT_MAX, false));
 
     if (!res)
-      res= open_query_tables(thd) || lock_query_tables(thd);
+      res= open_and_lock_tables(thd, m_lex->query_tables, true, 0);
 
     if (!res)
     {

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_acl.cc	revid:mattias.jonsson@stripped
@@ -3556,7 +3556,7 @@ int mysql_table_grant(THD *thd, TABLE_LI
       class LEX_COLUMN *column;
       List_iterator <LEX_COLUMN> column_iter(columns);
 
-      if (open_query_tables(thd))
+      if (open_normal_and_derived_tables(thd, table_list, 0))
         DBUG_RETURN(TRUE);
 
       while ((column = column_iter++))

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_base.cc	revid:mattias.jonsson@stripped
@@ -1567,8 +1567,13 @@ void close_thread_tables(THD *thd)
     /* Ensure we are calling ha_reset() for all used tables */
     mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
 
-    /* Set the tables_state to be able to reopen/reuse the tables */
-    thd->lex->tables_state= Query_tables_list::TABLES_STATE_REUSABLE;
+    /*
+      Mark this statement as one that has "unlocked" its tables.
+      For purposes of Query_tables_list::lock_tables_state we treat
+      any statement which passed through close_thread_tables() as
+      such.
+    */
+    thd->lex->lock_tables_state= Query_tables_list::LTS_NOT_LOCKED;
 
     /*
       We are under simple LOCK TABLES or we're inside a sub-statement
@@ -1611,9 +1616,11 @@ void close_thread_tables(THD *thd)
      */
     (void)thd->binlog_flush_pending_rows_event(TRUE);
     mysql_unlock_tables(thd, thd->lock);
-    thd->lex->tables_state= Query_tables_list::TABLES_STATE_UNLOCKED;
     thd->lock=0;
   }
+
+  thd->lex->lock_tables_state= Query_tables_list::LTS_NOT_LOCKED;
+
   /*
     Closing a MERGE child before the parent would be fatal if the
     other thread tries to abort the MERGE lock in between.
@@ -1621,8 +1628,6 @@ void close_thread_tables(THD *thd)
   if (thd->open_tables)
     close_open_tables(thd);
 
-  thd->lex->tables_state= Query_tables_list::TABLES_STATE_CLOSED;
-
   DBUG_VOID_RETURN;
 }
 
@@ -5662,101 +5667,6 @@ void open_and_lock_tables_cleanup(THD *t
 
 
 /**
-  Cleanup failed open or lock tables.
-
-  @param thd            Thread context.
-  @param mdl_savepoint  Savepoint for rollback.
-*/
-
-void open_and_lock_query_tables_cleanup(THD *thd)
-{
-  if (thd->lex->is_query_tables_opened())
-    open_and_lock_tables_cleanup(thd, thd->lex->mdl_open_savepoint);
-  thd->lex->tables_state= Query_tables_list::TABLES_STATE_CLOSED;
-}
-
-
-/**
-  Open query tables, open derived tables and prepares them.
-
-  @param         thd            Thread context.
-
-  @return Operation status
-    @retval false  OK
-    @retval true   Error
-*/
-
-bool open_query_tables(THD *thd)
-{
-  DBUG_ENTER("open_query_tables");
-
-  if (thd->lex->is_query_tables_opened())
-  {
-    DBUG_PRINT("info", ("Query tables already opened"));
-    DBUG_RETURN(false);
-  }
-
- 
-  thd->lex->mdl_open_savepoint= thd->mdl_context.mdl_savepoint();
-  
-  /* if prepare, then we must use shared mdl. */
-  if (open_tables(thd,
-                  &thd->lex->query_tables,
-                  &thd->lex->tables_lock_count,
-                  (thd->stmt_arena->is_stmt_prepare()
-                   ? MYSQL_OPEN_FORCE_SHARED_MDL : 0)))
-    DBUG_RETURN(true);
-
-  thd->lex->tables_state= Query_tables_list::TABLES_STATE_OPENED;
-
-  if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
-  {
-    open_and_lock_query_tables_cleanup(thd);
-    DBUG_RETURN(true);
-  }
-  
-  thd->lex->tables_state= Query_tables_list::TABLES_STATE_DERIVED_PREPARED;
-
-  DBUG_RETURN(false);
-}
-
-
-/**
-  Lock query tables.
-
-  @param         thd            Thread context.
-
-  @return Operation status
-    @retval false  OK
-    @retval true   Error
-*/
-
-bool lock_query_tables(THD *thd)
-{
-  DBUG_ENTER("lock_query_tables");
-
-  if (thd->lex->is_query_tables_locked())
-  {
-    DBUG_PRINT("info", ("Query tables already locked"));
-    DBUG_RETURN(false);
-  }
-
-  DBUG_ASSERT(thd->lex->tables_state >=
-              Query_tables_list::TABLES_STATE_OPENED);
-
-  if (lock_tables(thd,
-                  thd->lex->query_tables,
-                  thd->lex->tables_lock_count, 0))
-  {
-    open_and_lock_query_tables_cleanup(thd);
-    DBUG_RETURN(true);
-  }
-  thd->lex->tables_state= Query_tables_list::TABLES_STATE_LOCKED;
-  DBUG_RETURN(false);
-}
-
-
-/**
   Open all tables in list, locks them and optionally process derived tables.
 
   @param thd		      Thread context.
@@ -5808,34 +5718,33 @@ err:
 }
 
 
-/*
+/**
   Open all tables in list and process derived tables
 
-  SYNOPSIS
-    open_normal_and_derived_tables
-    thd		- thread handler
-    tables	- list of tables for open
-    flags       - bitmap of flags to modify how the tables will be open:
-                  MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
-                  done a flush on it.
+  @param       thd      thread handler
+  @param       tables   list of tables for open
+  @param       flags    bitmap of flags to modify how the tables will be open:
+                        MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
+                        done a flush on it.
 
-  RETURN
-    FALSE - ok
-    TRUE  - error
+  @retval FALSE - ok
+  @retval TRUE  - error
 
-  NOTE 
+  @note
     This is to be used on prepare stage when you don't read any
     data from the tables.
+
+  @note
+    Updates Query_tables_list::table_count as side-effect.
 */
 
 bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
 {
   DML_prelocking_strategy prelocking_strategy;
-  uint counter;
   MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
   DBUG_ENTER("open_normal_and_derived_tables");
-  DBUG_ASSERT(!thd->fill_derived_tables());
-  if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) ||
+  if (open_tables(thd, &tables, &thd->lex->table_count, flags,
+                  &prelocking_strategy) ||
       mysql_handle_derived(thd->lex, &mysql_derived_prepare))
     goto end;
 
@@ -5925,8 +5834,23 @@ bool lock_tables(THD *thd, TABLE_LIST *t
   DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
               !thd->lex->requires_prelocking());
 
+  /*
+    lock_tables() should not be called if this statement has
+    already locked its tables.
+  */
+  DBUG_ASSERT(thd->lex->lock_tables_state == Query_tables_list::LTS_NOT_LOCKED);
+
   if (!tables && !thd->lex->requires_prelocking())
+  {
+    /*
+      Even though we are not really locking any tables mark this
+      statement as one that has locked its tables, so we won't
+      call this function second time for the same execution of
+      the same statement.
+    */
+    thd->lex->lock_tables_state= Query_tables_list::LTS_LOCKED;
     DBUG_RETURN(thd->decide_logging_format(tables));
+  }
 
   /*
     Check for thd->locked_tables_mode to avoid a redundant
@@ -6079,6 +6003,13 @@ bool lock_tables(THD *thd, TABLE_LIST *t
     }
   }
 
+  /*
+    Mark the statement as having tables locked. For purposes
+    of Query_tables_list::lock_tables_state we treat any
+    statement which passes through lock_tables() as such.
+  */
+  thd->lex->lock_tables_state= Query_tables_list::LTS_LOCKED;
+
   DBUG_RETURN(thd->decide_logging_format(tables));
 }
 
@@ -9568,7 +9499,6 @@ open_system_tables_for_read(THD *thd, TA
     we also have to backup and reset/and then restore part of LEX
     which is accessed by open_tables() in order to determine if
     prelocking is needed and what tables should be added for it.
-    close_system_tables() doesn't require such treatment.
   */
   lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
   thd->reset_n_backup_open_tables_state(backup);
@@ -9607,7 +9537,16 @@ open_system_tables_for_read(THD *thd, TA
 void
 close_system_tables(THD *thd, Open_tables_backup *backup)
 {
+  Query_tables_list query_tables_list_backup;
+
+  /*
+    In order not affect execution of current statement we have to
+    backup/reset/restore Query_tables_list part of LEX, which is
+    accessed and updated in the process of closing tables.
+  */
+  thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
   close_thread_tables(thd);
+  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
   thd->restore_backup_open_tables_state(backup);
 }
 

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	revid:mattias.jonsson@stripped
+++ b/sql/sql_base.h	revid:mattias.jonsson@stripped
@@ -244,8 +244,6 @@ bool open_tables(THD *thd, TABLE_LIST **
                  Prelocking_strategy *prelocking_strategy);
 void open_and_lock_tables_cleanup(THD *thd,
                                   const MDL_savepoint &mdl_savepoint);
-void open_and_lock_query_tables_cleanup(THD *thd);
-bool open_query_tables(THD *thd);
 /* open_and_lock_tables with optional derived handling */
 bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
                           bool derived, uint flags,
@@ -256,7 +254,6 @@ TABLE *open_n_lock_single_table(THD *thd
                                 Prelocking_strategy *prelocking_strategy);
 bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
 bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
-bool lock_query_tables(THD *thd);
 void free_io_cache(TABLE *entry);
 void intern_close_table(TABLE *entry);
 bool close_thread_table(THD *thd, TABLE **table_ptr);

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_delete.cc	revid:mattias.jonsson@stripped
@@ -71,7 +71,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
   DBUG_ENTER("mysql_delete");
 
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, table_list, 0))
     DBUG_RETURN(TRUE);
 
   if (!(table= table_list->table))
@@ -118,7 +118,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
     goto exit_all_parts_pruned_away;
 #endif
 
-  if (lock_query_tables(thd))
+  if (lock_tables(thd, table_list, thd->lex->table_count, 0))
     DBUG_RETURN(true);
 
   const_cond= (!conds || conds->const_item());
@@ -556,19 +556,17 @@ extern "C" int refpos_order_cmp(const vo
   return file->cmp_ref((const uchar*)a, (const uchar*)b);
 }
 
-/*
-  make delete specific preparation and checks after opening tables
+/**
+  Make delete specific preparation and checks after opening tables.
 
-  SYNOPSIS
-    mysql_multi_delete_prepare()
-    thd         thread handler
+  @param      thd          Thread context.
+  @param[out] table_count  Number of tables to be deleted from.
 
-  RETURN
-    FALSE OK
-    TRUE  Error
+  @retval FALST - success.
+  @retval TRUE  - error.
 */
 
-int mysql_multi_delete_prepare(THD *thd)
+int mysql_multi_delete_prepare(THD *thd, uint *table_count)
 {
   LEX *lex= thd->lex;
   TABLE_LIST *aux_tables= lex->auxiliary_table_list.first;
@@ -588,6 +586,7 @@ int mysql_multi_delete_prepare(THD *thd)
                                     DELETE_ACL, SELECT_ACL))
     DBUG_RETURN(TRUE);
 
+  *table_count= 0;
 
   /*
     Multi-delete can't be constructed over-union => we always have
@@ -599,6 +598,8 @@ int mysql_multi_delete_prepare(THD *thd)
        target_tbl;
        target_tbl= target_tbl->next_local)
   {
+    ++(*table_count);
+
     if (!(target_tbl->table= target_tbl->correspondent_table->table))
     {
       DBUG_ASSERT(target_tbl->correspondent_table->view &&

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_insert.cc	revid:mattias.jonsson@stripped
@@ -743,7 +743,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   }
   else
   {
-    if (open_query_tables(thd))
+    if (open_normal_and_derived_tables(thd, table_list, 0))
       DBUG_RETURN(true);
   }
 
@@ -912,7 +912,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
   /* Lock the tables now if not delayed/already locked. */
   if (!is_locked &&
-      lock_query_tables(thd))
+      lock_tables(thd, table_list, thd->lex->table_count, 0))
     DBUG_RETURN(true);
  
   /*

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_lex.cc	revid:mattias.jonsson@stripped
@@ -2778,8 +2778,8 @@ void Query_tables_list::reset_query_tabl
   sroutines_list_own_elements= 0;
   binlog_stmt_flags= 0;
   stmt_accessed_table_flag= 0;
-  tables_state= TABLES_STATE_NONE;
-  tables_lock_count= 0;
+  lock_tables_state= LTS_NOT_LOCKED;
+  table_count= 0;
 }
 
 

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	revid:mattias.jonsson@stripped
+++ b/sql/sql_lex.h	revid:mattias.jonsson@stripped
@@ -46,7 +46,6 @@ class sys_var;
 class Item_func_match;
 class File_parser;
 class Key_part_spec;
-class MDL_savepoint;
 
 #ifdef MYSQL_SERVER
 /*
@@ -1069,50 +1068,36 @@ public:
   uint sroutines_list_own_elements;
 
   /**
-    Enum to track the state of the tables used by the query.
-  */
-  enum enum_tables_state {
-    /** The tables is not yet opened. */
-    TABLES_STATE_NONE = 0,
-    /**
-      The tables are already opened and locked in thd->open_tables,
-      but not marked as used.
-    */
-    TABLES_STATE_REUSABLE,
-    /** Base tables are opened. */
-    TABLES_STATE_OPENED,
-    /** Derived tables are prepared. */
-    TABLES_STATE_DERIVED_PREPARED,
-    /** Base tables are locked. */
-    TABLES_STATE_LOCKED,
-    /** Derived tables are optimized. */
-    TABLES_STATE_DERIVED_OPTIMIZED,
-    /** Derived tables are created for materialization. */
-    TABLES_STATE_DERIVED_CREATED,
-    /** Derived tables are materialized. */
-    TABLES_STATE_DERIVED_MATERIALIZED,
-    /** Base tables are unlocked. */
-    TABLES_STATE_UNLOCKED,
-    /** Base tables are closed or marked for reuse. */
-    TABLES_STATE_CLOSED
+    Locking state of tables in this particular statement.
+
+    If we under LOCK TABLES or in prelocked mode we consider tables
+    for the statement to be "locked" if there was a call to lock_tables()
+    (which called handler::start_stmt()) for tables of this statement
+    and there was no matching close_thread_tables() call.
+
+    As result this state may differ significantly from one represented
+    by Open_tables_state::lock/locked_tables_mode more, which are always
+    "on" under LOCK TABLES or in prelocked mode.
+  */
+  enum enum_lock_tables_state {
+    LTS_NOT_LOCKED = 0,
+    LTS_LOCKED
   };
-  enum_tables_state tables_state;
-  bool is_query_tables_opened()
-  {
-    if (tables_state >= TABLES_STATE_OPENED &&
-        tables_state < TABLES_STATE_CLOSED)
-      return true;
-    return false;
-  }
+  enum_lock_tables_state lock_tables_state;
   bool is_query_tables_locked()
   {
-    if (tables_state >= TABLES_STATE_LOCKED &&
-        tables_state < TABLES_STATE_UNLOCKED)
-      return true;
-    return false;
+    return (lock_tables_state == LTS_LOCKED);
   }
-  uint tables_lock_count;
-  MDL_savepoint mdl_open_savepoint;
+
+  /**
+    Number of tables which were open by open_tables() and to be locked
+    by lock_tables().
+    Note that we set this member only in some cases, when this value
+    needs to be passed from open_tables() to lock_tables() which are
+    separated by some amount of code.
+  */
+  uint table_count;
+
   /*
     These constructor and destructor serve for creation/destruction
     of Query_tables_list instances which are used as backup storage.

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_load.cc	revid:mattias.jonsson@stripped
@@ -228,9 +228,8 @@ int mysql_load(THD *thd,sql_exchange *ex
                  ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
   } 
 
-  if (open_query_tables(thd) || lock_query_tables(thd))
+  if (open_and_lock_tables(thd, table_list, TRUE, 0))
     DBUG_RETURN(TRUE);
-
   if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                     &thd->lex->select_lex.top_join_list,
                                     table_list,

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_parse.cc	revid:mattias.jonsson@stripped
@@ -2461,8 +2461,7 @@ case SQLCOM_PREPARE:
   }
   case SQLCOM_DO:
     if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
-        || open_query_tables(thd)
-        || lock_query_tables(thd))
+        || open_and_lock_tables(thd, all_tables, TRUE, 0))
       goto error;
 
     res= mysql_do(thd, *lex->insert_list);
@@ -2777,7 +2776,7 @@ case SQLCOM_PREPARE:
         goto end_with_restore_list;
       }
 
-      if (!(res= open_query_tables(thd)))
+      if (!(res= open_normal_and_derived_tables(thd, all_tables, 0)))
       {
         /* The table already exists */
         if (create_table->table || create_table->view)
@@ -3291,7 +3290,7 @@ end_with_restore_list:
 
     unit->set_limit(select_lex);
 
-    if (!(res= open_query_tables(thd)))
+    if (!(res= open_normal_and_derived_tables(thd, all_tables, 0)))
     {
       MYSQL_INSERT_SELECT_START(thd->query());
       /* Skip first table, which is the table we are inserting in */
@@ -3367,6 +3366,7 @@ end_with_restore_list:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
     TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
+    uint del_table_count;
     multi_delete *del_result;
 
     if ((res= multi_delete_precheck(thd, all_tables)))
@@ -3379,18 +3379,18 @@ end_with_restore_list:
       goto error;
 
     THD_STAGE_INFO(thd, stage_init);
-    if ((res= open_query_tables(thd)))
+    if ((res= open_normal_and_derived_tables(thd, all_tables, 0)))
       break;
 
     MYSQL_MULTI_DELETE_START(thd->query());
-    if ((res= mysql_multi_delete_prepare(thd)))
+    if ((res= mysql_multi_delete_prepare(thd, &del_table_count)))
     {
       MYSQL_MULTI_DELETE_DONE(1, 0);
       goto error;
     }
 
     if (!thd->is_fatal_error &&
-        (del_result= new multi_delete(aux_tables, lex->tables_lock_count)))
+        (del_result= new multi_delete(aux_tables, del_table_count)))
     {
       if (lex->describe)
         res= explain_multi_table_modification(thd, del_result);
@@ -3506,9 +3506,8 @@ end_with_restore_list:
   {
     List<set_var_base> *lex_var_list= &lex->var_list;
 
-    if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
-        || open_query_tables(thd)
-        || lock_query_tables(thd))
+    if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)
+         || open_and_lock_tables(thd, all_tables, TRUE, 0)))
       goto error;
     if (!(res= sql_set_variables(thd, lex_var_list)))
     {
@@ -4293,8 +4292,7 @@ create_sp_error:
       */
       if (check_table_access(thd, SELECT_ACL, all_tables, FALSE,
                              UINT_MAX, FALSE) ||
-          open_query_tables(thd) ||
-          lock_query_tables(thd))
+          open_and_lock_tables(thd, all_tables, TRUE, 0))
        goto error;
 
       /*
@@ -4865,7 +4863,7 @@ static bool execute_sqlcom_select(THD *t
       param->select_limit=
         new Item_int((ulonglong) thd->variables.select_limit);
   }
-  if (!(res= open_query_tables(thd)))
+  if (!(res= open_normal_and_derived_tables(thd, all_tables, 0)))
   {
     if (lex->describe)
     {

=== modified file 'sql/sql_parse.h'
--- a/sql/sql_parse.h	revid:mattias.jonsson@stripped
+++ b/sql/sql_parse.h	revid:mattias.jonsson@stripped
@@ -42,7 +42,7 @@ bool select_precheck(THD *thd, LEX *lex,
 bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
 bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
 int mysql_multi_update_prepare(THD *thd);
-int mysql_multi_delete_prepare(THD *thd);
+int mysql_multi_delete_prepare(THD *thd, uint *table_count);
 bool mysql_insert_select_prepare(THD *thd);
 bool update_precheck(THD *thd, TABLE_LIST *tables);
 bool delete_precheck(THD *thd, TABLE_LIST *tables);

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_prepare.cc	revid:mattias.jonsson@stripped
@@ -90,7 +90,7 @@ When one supplies long data for a placeh
 #include "set_var.h"
 #include "sql_prepare.h"
 #include "sql_parse.h" // insert_precheck, update_precheck, delete_precheck
-#include "sql_base.h"  // open_query_tables
+#include "sql_base.h"  // open_normal_and_derived_tables
 #include "sql_cache.h"                          // query_cache_*
 #include "sql_view.h"                          // create_view_precheck
 #include "sql_delete.h"                        // mysql_prepare_delete
@@ -1269,7 +1269,8 @@ static bool mysql_test_insert(Prepared_s
     If we would use locks, then we have to ensure we are not using
     TL_WRITE_DELAYED as having two such locks can cause table corruption.
   */
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, table_list,
+                                     MYSQL_OPEN_FORCE_SHARED_MDL))
     goto error;
 
   if ((values= its++))
@@ -1349,7 +1350,8 @@ static int mysql_test_update(Prepared_st
   DBUG_ENTER("mysql_test_update");
 
   if (update_precheck(thd, table_list) ||
-      open_query_tables(thd))
+      open_normal_and_derived_tables(thd, table_list,
+                                     MYSQL_OPEN_FORCE_SHARED_MDL))
     goto error;
 
   if (table_list->multitable_view)
@@ -1426,7 +1428,8 @@ static bool mysql_test_delete(Prepared_s
   DBUG_ASSERT(stmt->is_stmt_prepare());
 
   if (delete_precheck(thd, table_list) ||
-      open_query_tables(thd))
+      open_normal_and_derived_tables(thd, table_list,
+                                     MYSQL_OPEN_FORCE_SHARED_MDL))
     goto error;
 
   if (!table_list->table)
@@ -1478,7 +1481,7 @@ static int mysql_test_select(Prepared_st
     goto error;
   }
 
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     goto error;
 
   thd->lex->used_tables= 0;                        // Updated by setup_fields
@@ -1540,7 +1543,7 @@ static bool mysql_test_do_fields(Prepare
                                    UINT_MAX, FALSE))
     DBUG_RETURN(TRUE);
 
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     DBUG_RETURN(TRUE);
   DBUG_RETURN(setup_fields(thd, Ref_ptr_array(),
                            *values, MARK_COLUMNS_NONE, 0, 0));
@@ -1572,7 +1575,7 @@ static bool mysql_test_set_fields(Prepar
 
   if ((tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
                                     UINT_MAX, FALSE)) ||
-      open_query_tables(thd))
+      open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     goto error;
 
   while ((var= it++))
@@ -1609,7 +1612,7 @@ static bool mysql_test_call_fields(Prepa
 
   if ((tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
                                     UINT_MAX, FALSE)) ||
-      open_query_tables(thd))
+      open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     goto err;
 
   while ((item= it++))
@@ -1689,11 +1692,12 @@ select_like_stmt_test_with_open(Prepared
 
   /*
     We should not call LEX::unit.cleanup() after this
-    open_query_tables() call because we don't allow
+    open_normal_and_derived_tables() call because we don't allow
     prepared EXPLAIN yet so derived tables will clean up after
     themself.
   */
-  if (open_query_tables(stmt->thd))
+  if (open_normal_and_derived_tables(stmt->thd, tables,
+                                     MYSQL_OPEN_FORCE_SHARED_MDL))
     DBUG_RETURN(TRUE);
 
   DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
@@ -1734,7 +1738,8 @@ static bool mysql_test_create_table(Prep
     if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
       create_table->open_type= OT_BASE_ONLY;
 
-    if (open_query_tables(stmt->thd))
+    if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
+                                       MYSQL_OPEN_FORCE_SHARED_MDL))
       DBUG_RETURN(TRUE);
 
     select_lex->context.resolve_in_select_list= TRUE;
@@ -1753,7 +1758,8 @@ static bool mysql_test_create_table(Prep
       we validate metadata of all CREATE TABLE statements,
       which keeps metadata validation code simple.
     */
-    if (open_query_tables(stmt->thd))
+    if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
+                                       MYSQL_OPEN_FORCE_SHARED_MDL))
       DBUG_RETURN(TRUE);
   }
 
@@ -1794,7 +1800,7 @@ static bool mysql_test_create_view(Prepa
   if (open_temporary_tables(thd, tables))
     goto err;
 
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     goto err;
 
   lex->context_analysis_only|=  CONTEXT_ANALYSIS_ONLY_VIEW;
@@ -1834,6 +1840,18 @@ static bool mysql_test_multiupdate(Prepa
 
 
 /**
+  Wrapper for mysql_multi_delete_prepare() function which makes
+  it compatible with select_like_stmt_test_with_open().
+*/
+
+static int mysql_multi_delete_prepare_tester(THD *thd)
+{
+  uint table_count;
+  return mysql_multi_delete_prepare(thd, &table_count);
+}
+
+
+/**
   Validate and prepare for execution a multi delete statement.
 
   @param stmt               prepared statement
@@ -1857,7 +1875,7 @@ static bool mysql_test_multidelete(Prepa
 
   if (multi_delete_precheck(stmt->thd, tables) ||
       select_like_stmt_test_with_open(stmt, tables,
-                                      &mysql_multi_delete_prepare,
+                                      &mysql_multi_delete_prepare_tester,
                                       OPTION_SETUP_TABLES_DONE))
     goto error;
   if (!tables->table)
@@ -1874,13 +1892,13 @@ error:
 
 /**
   Wrapper for mysql_insert_select_prepare, to make change of local tables
-  after open_query_tables() call.
+  after open_normal_and_derived_tables() call.
 
   @param thd                thread handle
 
   @note
     We need to remove the first local table after
-    open_query_tables(), because mysql_handle_derived
+    open_normal_and_derived_tables(), because mysql_handle_derived
     uses local tables lists.
 */
 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_select.cc	revid:mattias.jonsson@stripped
@@ -1166,16 +1166,12 @@ mysql_select(THD *thd,
              SELECT_LEX *select_lex)
 {
   bool free_join= 1;
-  bool store_in_query_cache= false;
   uint og_num= 0;
   ORDER *first_order= NULL;
   ORDER *first_group= NULL;
   JOIN *join= NULL;
   DBUG_ENTER("mysql_select");
 
-  if (open_query_tables(thd))
-    DBUG_RETURN(true);
-  
   if (order)
   {
     og_num= order->elements;
@@ -1187,10 +1183,6 @@ mysql_select(THD *thd,
     first_group= group->first;
   }
 
-  /* Only register the query if it was opened above. */
-  if (thd->lex->tables_state < Query_tables_list::TABLES_STATE_LOCKED)
-    store_in_query_cache= true;
-
   if (mysql_prepare_select(thd, tables, wild_num, fields,
                            conds, og_num, first_order, first_group, having,
                            proc_param, select_options, result, unit,
@@ -1204,23 +1196,36 @@ mysql_select(THD *thd,
     DBUG_RETURN(true);
   }
 
-  if (lock_query_tables(thd))
+  if (! thd->lex->is_query_tables_locked())
   {
-    if (free_join)
+    /*
+      If tables are not locked at this point, it means that we have delayed
+      this step until after prepare stage (i.e. this moment). This allows to
+      do better partition pruning and avoid locking unused partitions.
+      As a consequence, in such a case, prepare stage can rely only on
+      metadata about tables used and not data from them.
+      We need to lock tables now in order to proceed with the remaning
+      stages of query optimization and execution.
+    */
+    if (lock_tables(thd, thd->lex->query_tables, thd->lex->table_count, 0))
     {
-      thd_proc_info(thd, "end");
-      (void) select_lex->cleanup();
+      if (free_join)
+      {
+        thd_proc_info(thd, "end");
+        (void) select_lex->cleanup();
+      }
+      DBUG_RETURN(true);
     }
-    DBUG_RETURN(true);
-  }
 
-  /*
-    Tables must be locked before storing the query in the query cache.
-    Transactional engines must been signalled that the statement started,
-    which external_lock signals.
-  */
-  if (store_in_query_cache)
+    /*
+      Only register query in cache if it tables were locked above.
+
+      Tables must be locked before storing the query in the query cache.
+      Transactional engines must been signalled that the statement started,
+      which external_lock signals.
+    */
     query_cache_store_query(thd, thd->lex->query_tables);
+  }
 
   if (mysql_execute_select(thd, select_lex, free_join, join))
     DBUG_RETURN(true);

=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_union.cc	revid:mattias.jonsson@stripped
@@ -34,31 +34,36 @@ bool mysql_union(THD *thd, LEX *lex, sel
                  SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
 {
   bool res;
-  bool store_in_query_cache= false;
   DBUG_ENTER("mysql_union");
 
-  if (open_query_tables(thd))
-    DBUG_RETURN(true);
-
-  /* Only register the query if it was opened above */
-  if (thd->lex->tables_state < Query_tables_list::TABLES_STATE_LOCKED)
-    store_in_query_cache= true;
-
   res= unit->prepare(thd, result,
 		     SELECT_NO_UNLOCK | setup_tables_done_option);
   if (res)
     goto err;
 
-  if (lock_query_tables(thd))
-    goto err;
+  if (! thd->lex->is_query_tables_locked())
+  {
+    /*
+      If tables are not locked at this point, it means that we have delayed
+      this step until after prepare stage (i.e. this moment). This allows to
+      do better partition pruning and avoid locking unused partitions.
+      As a consequence, in such a case, prepare stage can rely only on
+      metadata about tables used and not data from them.
+      We need to lock tables now in order to proceed with the remaning
+      stages of query optimization and execution.
+    */
+    if (lock_tables(thd, lex->query_tables, lex->table_count, 0))
+      goto err;
 
-  /*
-    Tables must be locked before storing the query in the query cache.
-    Transactional engines must been signalled that the statement started,
-    which external_lock signals.
-  */
-  if (store_in_query_cache)
+    /*
+      Only register query in cache if it tables were locked above.
+
+      Tables must be locked before storing the query in the query cache.
+      Transactional engines must been signalled that the statement started,
+      which external_lock signals.
+    */
     query_cache_store_query(thd, thd->lex->query_tables);
+  }
 
   res= unit->optimize() || unit->exec();
   res|= unit->cleanup();

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_update.cc	revid:mattias.jonsson@stripped
@@ -288,7 +288,7 @@ int mysql_update(THD *thd,
 
   DBUG_ENTER("mysql_update");
 
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, table_list, 0))
     DBUG_RETURN(1);
 
   if (table_list->multitable_view)
@@ -438,7 +438,7 @@ int mysql_update(THD *thd,
       bitmap_copy(&table->part_info->lock_partitions, &lock_partitions);
   }
 #endif
-  if (lock_query_tables(thd))
+  if (lock_tables(thd, table_list, thd->lex->table_count, 0))
     DBUG_RETURN(1);
 
   /* Update the table->file->stats.records number */
@@ -1294,7 +1294,10 @@ int mysql_multi_update_prepare(THD *thd)
     keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
     and global read lock.
   */
-  if (original_multiupdate && open_query_tables(thd))
+  if (original_multiupdate &&
+      open_normal_and_derived_tables(thd, table_list,
+                                     (thd->stmt_arena->is_stmt_prepare() ?
+                                      MYSQL_OPEN_FORCE_SHARED_MDL : 0)))
     DBUG_RETURN(TRUE);
   /*
     setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	revid:mattias.jonsson@stripped
+++ b/sql/sql_view.cc	revid:mattias.jonsson@stripped
@@ -449,7 +449,7 @@ bool mysql_create_view(THD *thd, TABLE_L
   }
 
   /* Not required to lock any tables. */
-  if (open_query_tables(thd))
+  if (open_normal_and_derived_tables(thd, lex->query_tables, 0))
   {
     view= lex->unlink_first_table(&link_to_local);
     res= TRUE;

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (mattias.jonsson:3875 to 3876) WL#4443Mattias Jonsson10 Apr