List:Commits« Previous MessageNext Message »
From:Dmitry Shulga Date:May 20 2011 7:11pm
Subject:bzr commit into mysql-trunk branch (Dmitry.Shulga:3377) Bug#38813
Bug#11749345
View as plain text  
#At file:///Users/shulga/projects/mysql/mysql-trunk/ based on revid:mayank.prasad@stripped

 3377 Dmitry Shulga	2011-05-21 [merge]
      Manual merge of patch for Bug#11749345 (formerly known as bug#38813)
      from 5.5->trunk.

    modified:
      sql/sql_show.cc
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2011-05-04 07:51:15 +0000
+++ b/sql/sql_show.cc	2011-05-20 19:09:31 +0000
@@ -2408,12 +2408,11 @@ bool schema_table_store_record(THD *thd,
 }
 
 
-int make_table_list(THD *thd, SELECT_LEX *sel,
-                    LEX_STRING *db_name, LEX_STRING *table_name)
+static int make_table_list(THD *thd, SELECT_LEX *sel,
+                           LEX_STRING *db_name, LEX_STRING *table_name)
 {
   Table_ident *table_ident;
   table_ident= new Table_ident(thd, *db_name, *table_name, 1);
-  sel->init_query();
   if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
     return 1;
   return 0;
@@ -2983,98 +2982,196 @@ make_table_name_list(THD *thd, List<LEX_
 
 
 /**
-  @brief          Fill I_S table for SHOW COLUMNS|INDEX commands
+  Fill I_S table with data obtained by performing full-blown table open.
 
-  @param[in]      thd                      thread handler
-  @param[in]      tables                   TABLE_LIST for I_S table
-  @param[in]      schema_table             pointer to I_S structure
-  @param[in]      can_deadlock             Indicates that deadlocks are possible
-                                           due to metadata locks, so to avoid
-                                           them we should not wait in case if
-                                           conflicting lock is present.
-  @param[in]      open_tables_state_backup pointer to Open_tables_backup object
-                                           which is used to save|restore original
-                                           status of variables related to
-                                           open tables state
+  @param  thd                       Thread handler.
+  @param  is_show_fields_or_keys    Indicates whether it is a legacy SHOW
+                                    COLUMNS or SHOW KEYS statement.
+  @param  table                     TABLE object for I_S table to be filled.
+  @param  schema_table              I_S table description structure.
+  @param  orig_db_name              Database name.
+  @param  orig_table_name           Table name.
+  @param  open_tables_state_backup  Open_tables_state object which is used
+                                    to save/restore original status of
+                                    variables related to open tables state.
+  @param  can_deadlock              Indicates that deadlocks are possible
+                                    due to metadata locks, so to avoid
+                                    them we should not wait in case if
+                                    conflicting lock is present.
 
-  @return         Operation status
-    @retval       0           success
-    @retval       1           error
+  @retval FALSE - Success.
+  @retval TRUE  - Failure.
 */
+static bool
+fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
+                          TABLE *table, ST_SCHEMA_TABLE *schema_table,
+                          LEX_STRING *orig_db_name,
+                          LEX_STRING *orig_table_name,
+                          Open_tables_backup *open_tables_state_backup,
+                          bool can_deadlock)
+{
+  Query_arena i_s_arena(thd->mem_root,
+                        Query_arena::STMT_CONVENTIONAL_EXECUTION),
+              backup_arena, *old_arena;
+  LEX *old_lex= thd->lex, temp_lex, *lex;
+  LEX_STRING db_name, table_name;
+  TABLE_LIST *table_list;
+  bool result= true;
 
-static int 
-fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
-                              ST_SCHEMA_TABLE *schema_table,
-                              bool can_deadlock,
-                              Open_tables_backup *open_tables_state_backup)
-{
-  LEX *lex= thd->lex;
-  bool res;
-  LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
-  enum_sql_command save_sql_command= lex->sql_command;
-  TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first;
-  TABLE *table= tables->table;
-  int error= 1;
-  DBUG_ENTER("fill_schema_show");
+  DBUG_ENTER("fill_schema_table_by_open");
+  /*
+    When a view is opened its structures are allocated on a permanent
+    statement arena and linked into the LEX tree for the current statement
+    (this happens even in cases when view is handled through TEMPTABLE
+    algorithm).
+
+    To prevent this process from unnecessary hogging of memory in the permanent
+    arena of our I_S query and to avoid damaging its LEX we use temporary
+    arena and LEX for table/view opening.
+
+    Use temporary arena instead of statement permanent arena. Also make
+    it active arena and save original one for successive restoring.
+  */
+  old_arena= thd->stmt_arena;
+  thd->stmt_arena= &i_s_arena;
+  thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
+
+  /* Prepare temporary LEX. */
+  thd->lex= lex= &temp_lex;
+  lex_start(thd);
+
+  /* Disable constant subquery evaluation as we won't be locking tables. */
+  lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
+
+  /*
+    Some of process_table() functions rely on wildcard being passed from
+    old LEX (or at least being initialized).
+  */
+  lex->wild= old_lex->wild;
 
-  lex->all_selects_list= tables->schema_select_lex;
   /*
-    Restore thd->temporary_tables to be able to process
-    temporary tables(only for 'show index' & 'show columns').
-    This should be changed when processing of temporary tables for
-    I_S tables will be done.
+    Since make_table_list() might change database and table name passed
+    to it we create copies of orig_db_name and orig_table_name here.
+    These copies are used for make_table_list() while unaltered values
+    are passed to process_table() functions.
   */
-  thd->temporary_tables= open_tables_state_backup->temporary_tables;
+  if (!thd->make_lex_string(&db_name, orig_db_name->str,
+                            orig_db_name->length, FALSE) ||
+      !thd->make_lex_string(&table_name, orig_table_name->str,
+                            orig_table_name->length, FALSE))
+    goto end;
+
+  /*
+    Create table list element for table to be open. Link it with the
+    temporary LEX. The latter is required to correctly open views and
+    produce table describing their structure.
+  */
+  if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
+    goto end;
+
+  table_list= lex->select_lex.table_list.first;
+
+  if (is_show_fields_or_keys)
+  {
+    /*
+      Restore thd->temporary_tables to be able to process
+      temporary tables (only for 'show index' & 'show columns').
+      This should be changed when processing of temporary tables for
+      I_S tables will be done.
+    */
+    thd->temporary_tables= open_tables_state_backup->temporary_tables;
+  }
+  else
+  {
+    /*
+      Apply optimization flags for table opening which are relevant for
+      this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
+      backward compatibility.
+    */
+    table_list->i_s_requested_object= schema_table->i_s_requested_object;
+  }
+
   /*
     Let us set fake sql_command so views won't try to merge
     themselves into main statement. If we don't do this,
     SELECT * from information_schema.xxxx will cause problems.
-    SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' 
+    SQLCOM_SHOW_FIELDS is used because it satisfies
+    'only_view_structure()'.
   */
   lex->sql_command= SQLCOM_SHOW_FIELDS;
 
-  res= open_temporary_tables(thd, show_table_list);
+  result= open_temporary_tables(thd, table_list);
 
-  if (!res)
+  if (!result)
   {
-    res= open_normal_and_derived_tables(thd, show_table_list,
-                                        (MYSQL_OPEN_IGNORE_FLUSH |
-                                         MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
-                                         (can_deadlock ?
-                                          MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
+    result= open_normal_and_derived_tables(thd, table_list,
+                                           (MYSQL_OPEN_IGNORE_FLUSH |
+                                            MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
+                                            (can_deadlock ?
+                                             MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
   }
-
-  lex->sql_command= save_sql_command;
+  /*
+    Restore old value of sql_command back as it is being looked at in
+    process_table() function.
+  */
+  lex->sql_command= old_lex->sql_command;
 
   DEBUG_SYNC(thd, "after_open_table_ignore_flush");
 
   /*
-    get_all_tables() returns 1 on failure and 0 on success thus
-    return only these and not the result code of ::process_table()
+    XXX:  show_table_list has a flag i_is_requested,
+    and when it's set, open_normal_and_derived_tables()
+    can return an error without setting an error message
+    in THD, which is a hack. This is why we have to
+    check for res, then for thd->is_error() and only then
+    for thd->main_da.sql_errno().
 
-    We should use show_table_list->alias instead of 
-    show_table_list->table_name because table_name
-    could be changed during opening of I_S tables. It's safe
-    to use alias because alias contains original table name 
-    in this case(this part of code is used only for 
-    'show columns' & 'show statistics' commands).
+    Again we don't do this for SHOW COLUMNS/KEYS because
+    of backward compatibility.
   */
-   table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
-                                    strlen(show_table_list->alias), FALSE);
-   if (!show_table_list->view)
-     db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db,
-                                   show_table_list->db_length, FALSE);
-   else
-     db_name= &show_table_list->view_db;
-      
-
-   error= test(schema_table->process_table(thd, show_table_list,
-                                           table, res, db_name,
-                                           table_name));
-   thd->temporary_tables= 0;
-   close_tables_for_reopen(thd, &show_table_list,
-                           open_tables_state_backup->mdl_system_tables_svp);
-   DBUG_RETURN(error);
+  if (!is_show_fields_or_keys && result && thd->is_error() &&
+      thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
+  {
+    /*
+      Hide error for a non-existing table.
+      For example, this error can occur when we use a where condition
+      with a db name and table, but the table does not exist.
+    */
+    result= false;
+    thd->clear_error();
+  }
+  else
+  {
+    result= schema_table->process_table(thd, table_list,
+                                        table, result,
+                                        orig_db_name,
+                                        orig_table_name);
+  }
+
+
+end:
+  lex->unit.cleanup();
+
+  /* Restore original LEX value, statement's arena and THD arena values. */
+  lex_end(thd->lex);
+
+  if (i_s_arena.free_list)
+    i_s_arena.free_items();
+
+  /*
+    For safety reset list of open temporary tables before closing
+    all tables open within this Open_tables_state.
+  */
+  thd->temporary_tables= NULL;
+  close_thread_tables(thd);
+  thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
+
+  thd->lex= old_lex;
+
+  thd->stmt_arena= old_arena;
+  thd->restore_active_arena(&i_s_arena, &backup_arena);
+
+  DBUG_RETURN(result);
 }
 
 
@@ -3485,10 +3582,8 @@ int get_all_tables(THD *thd, TABLE_LIST 
 {
   LEX *lex= thd->lex;
   TABLE *table= tables->table;
-  SELECT_LEX *old_all_select_lex= lex->all_selects_list;
   SELECT_LEX *lsel= tables->schema_select_lex;
   ST_SCHEMA_TABLE *schema_table= tables->schema_table;
-  SELECT_LEX sel;
   LOOKUP_FIELD_VALUES lookup_field_vals;
   LEX_STRING *db_name, *table_name;
   bool with_i_schema;
@@ -3496,11 +3591,8 @@ int get_all_tables(THD *thd, TABLE_LIST 
   List<LEX_STRING> db_names;
   List_iterator_fast<LEX_STRING> it(db_names);
   Item *partial_cond= 0;
-  uint derived_tables= lex->derived_tables; 
   int error= 1;
   Open_tables_backup open_tables_state_backup;
-  uint8 save_context_analysis_only= lex->context_analysis_only;
-  Query_tables_list query_tables_list_backup;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   Security_context *sctx= thd->security_ctx;
 #endif
@@ -3519,15 +3611,6 @@ int get_all_tables(THD *thd, TABLE_LIST 
   */
   can_deadlock= thd->mdl_context.has_locks();
 
-  lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
-  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
-  /*
-    Restore Query_tables_list::sql_command value, which was reset
-    above, as ST_SCHEMA_TABLE::process_table() functions often rely
-    that this value reflects which SHOW statement is executed.
-  */
-  lex->sql_command= query_tables_list_backup.sql_command;
-
   /*
     We should not introduce deadlocks even if we already have some
     tables open and locked, since we won't lock tables which we will
@@ -3547,9 +3630,19 @@ int get_all_tables(THD *thd, TABLE_LIST 
   */
   if (lsel && lsel->table_list.first)
   {
-    error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
-                                         can_deadlock,
-                                         &open_tables_state_backup);
+    LEX_STRING db_name, table_name;
+
+    db_name.str= lsel->table_list.first->db;
+    db_name.length= lsel->table_list.first->db_length;
+
+    table_name.str= lsel->table_list.first->table_name;
+    table_name.length= lsel->table_list.first->table_name_length;
+
+    error= fill_schema_table_by_open(thd, TRUE,
+                                     table, schema_table,
+                                     &db_name, &table_name,
+                                     &open_tables_state_backup,
+                                     can_deadlock);
     goto err;
   }
 
@@ -3603,12 +3696,6 @@ int get_all_tables(THD *thd, TABLE_LIST 
   it.rewind(); /* To get access to new elements in basis list */
   while ((db_name= it++))
   {
-    LEX_STRING orig_db_name;
-
-    /* db_name can be changed in make_table_list() func */
-    if (!thd->make_lex_string(&orig_db_name, db_name->str,
-                              db_name->length, FALSE))
-      goto err;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
     if (!(check_access(thd, SELECT_ACL, db_name->str,
                        &thd->col_access, NULL, 0, 1) ||
@@ -3686,66 +3773,11 @@ int get_all_tables(THD *thd, TABLE_LIST 
                 continue;
             }
 
-            int res;
-            LEX_STRING tmp_lex_string;
-            /*
-              Set the parent lex of 'sel' because it is needed by
-              sel.init_query() which is called inside make_table_list.
-            */
-            sel.parent_lex= lex;
-            if (make_table_list(thd, &sel, db_name, table_name))
-              goto err;
-            TABLE_LIST *show_table_list= sel.table_list.first;
-            lex->all_selects_list= &sel;
-            lex->derived_tables= 0;
-            lex->sql_command= SQLCOM_SHOW_FIELDS;
-            show_table_list->i_s_requested_object=
-              schema_table->i_s_requested_object;
-            DEBUG_SYNC(thd, "before_open_in_get_all_tables");
-            res= open_normal_and_derived_tables(thd, show_table_list,
-                   (MYSQL_OPEN_IGNORE_FLUSH |
-                    MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
-                    (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
-            lex->sql_command= query_tables_list_backup.sql_command;
-            /*
-              XXX:  show_table_list has a flag i_is_requested,
-              and when it's set, open_normal_and_derived_tables()
-              can return an error without setting an error message
-              in THD, which is a hack. This is why we have to
-              check for res, then for thd->is_error() only then
-              for thd->stmt_da->sql_errno().
-            */
-            if (res && thd->is_error() &&
-                thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
-            {
-              /*
-                Hide error for not existing table.
-                This error can occur for example when we use
-                where condition with db name and table name and this
-                table does not exist.
-              */
-              res= 0;
-              thd->clear_error();
-            }
-            else
-            {
-              /*
-                We should use show_table_list->alias instead of 
-                show_table_list->table_name because table_name
-                could be changed during opening of I_S tables. It's safe
-                to use alias because alias contains original table name 
-                in this case.
-              */
-              thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
-                                   strlen(show_table_list->alias), FALSE);
-              res= schema_table->process_table(thd, show_table_list, table,
-                                               res, &orig_db_name,
-                                               &tmp_lex_string);
-              close_tables_for_reopen(thd, &show_table_list,
-                                      open_tables_state_backup.mdl_system_tables_svp);
-            }
-            DBUG_ASSERT(!lex->query_tables_own_last);
-            if (res)
+            if (fill_schema_table_by_open(thd, FALSE,
+                                          table, schema_table,
+                                          db_name, table_name,
+                                          &open_tables_state_backup,
+                                          can_deadlock))
               goto err;
           }
         }
@@ -3761,10 +3793,7 @@ int get_all_tables(THD *thd, TABLE_LIST 
   error= 0;
 err:
   thd->restore_backup_open_tables_state(&open_tables_state_backup);
-  lex->restore_backup_query_tables_list(&query_tables_list_backup);
-  lex->derived_tables= derived_tables;
-  lex->all_selects_list= old_all_select_lex;
-  lex->context_analysis_only= save_context_analysis_only;
+
   DBUG_RETURN(error);
 }
 


Attachment: [text/bzr-bundle] bzr/dmitry.shulga@oracle.com-20110520190931-imdp7k2jt9wi83or.bundle
Thread
bzr commit into mysql-trunk branch (Dmitry.Shulga:3377) Bug#38813Bug#11749345Dmitry Shulga20 May