List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:December 2 2010 6:57am
Subject:bzr commit into mysql-trunk-bugfixing branch (Dmitry.Lenev:3394) Bug#27480
View as plain text  
#At file:///home/dlenev/src/bzr/mysql-trunk-bugfixing-bug27480/ based on revid:dmitry.lenev@stripped

 3394 Dmitry Lenev	2010-12-02
      Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES
      privilege to allow temp table operations).
      
      Review fixes in progress. Streamline handling of temporary tables
      for prelocking list elements.

    modified:
      sql/sp_head.cc
      sql/sql_base.cc
      sql/sql_prepare.cc
      sql/sql_view.cc
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2010-11-30 08:30:48 +0000
+++ b/sql/sp_head.cc	2010-12-02 06:57:30 +0000
@@ -4176,11 +4176,6 @@ sp_head::add_used_tables_to_table_list(T
       table->prelocking_placeholder= 1;
       table->belong_to_view= belong_to_view;
       table->trg_event_map= stab->trg_event_map;
-
-      table->open_type=
-        find_temporary_table(thd, table->db, table->table_name) ?
-        OT_TEMPORARY_OR_BASE : OT_BASE_ONLY;
-
       /*
         Since we don't allow DDL on base tables in prelocked mode it
         is safe to infer the type of metadata lock from the type of

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2010-11-29 14:13:07 +0000
+++ b/sql/sql_base.cc	2010-12-02 06:57:30 +0000
@@ -4320,37 +4320,45 @@ open_and_process_table(THD *thd, LEX *le
 
   if (tables->prelocking_placeholder)
   {
-    if (tables->open_type == OT_TEMPORARY_OR_BASE)
+    /*
+      We're opening a table from the prelocking list.
+
+      Since this table list element might have been added after pre-opening
+      of temporary tables we have to try to open temporary table for it.
+
+      We can't simply skip this table list element and postpone opening of
+      temporary tabletill the execution of substatement for several reasons:
+      - Temporary table can be a MERGE table with base underlying tables,
+        so its underlying tables has to be properly open and locked at
+        prelocking stage. TODO/FIXME: Add test case for this scenario.
+      - Temporary table can be a MERGE table and we might be in PREPARE
+        phase for a prepared statement. In this case it is important to call
+        HA_ATTACH_CHILDREN for all merge children.
+        This is necessary because merge children remember "TABLE_SHARE ref type"
+        and "TABLE_SHARE def version" in the HA_ATTACH_CHILDREN operation.
+        If HA_ATTACH_CHILDREN is not called, these attributes are not set.
+        Then, during the first EXECUTE, those attributes need to be updated.
+        That would cause statement re-preparing (because changing those
+        attributes during EXECUTE is caught by THD::m_reprepare_observer).
+        The problem is that since those attributes are not set in merge
+        children, another round of PREPARE will not help.
+    */
+    error= open_and_process_temporary_table(thd, tables);
+
+    if (!error && !tables->table)
     {
       /*
-        We're opening a table from the prelocking list. When adding to this
-        list, TABLE_LIST::open_type is set as follows:
-          - if there is a temporary table with that name,
-            open_type is OT_TEMPORARY_OR_BASE (there might be also a base
-            table, but that's not important because temporary tables take
-            precedence over base ones);
-          - otherwise (no temporary table), open_type is OT_BASE_ONLY.
-
-        If there is a temporary table for that TABLE_LIST instance, there
-        is no reason to pre-open base table. Proper table will be choosen
-        and opened during execution.
+        For the tables added by the pre-locking code, attempt to open
+        the table but fail silently if the table does not exist.
+        The real failure will occur when/if a statement attempts to use
+        that table.
       */
-      DBUG_RETURN(FALSE);
+      No_such_table_error_handler no_such_table_handler;
+      thd->push_internal_handler(&no_such_table_handler);
+      error= open_table(thd, tables, new_frm_mem, ot_ctx);
+      thd->pop_internal_handler();
+      safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
     }
-
-    DBUG_ASSERT(tables->open_type == OT_BASE_ONLY);
-
-    /*
-      For the tables added by the pre-locking code, attempt to open
-      the table but fail silently if the table does not exist.
-      The real failure will occur when/if a statement attempts to use
-      that table.
-    */
-    No_such_table_error_handler no_such_table_handler;
-    thd->push_internal_handler(&no_such_table_handler);
-    error= open_table(thd, tables, new_frm_mem, ot_ctx);
-    thd->pop_internal_handler();
-    safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
   }
   else
     error= open_table(thd, tables, new_frm_mem, ot_ctx);

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-11-29 14:13:07 +0000
+++ b/sql/sql_prepare.cc	2010-12-02 06:57:30 +0000
@@ -2125,87 +2125,6 @@ static bool check_prepared_statement(Pre
     break;
   }
 
-  /*
-    Open temporary tables added by prelocking.
-
-    Here we need to open temporary tables added by prelocking and ensure
-    that HA_ATTACH_CHILDREN is called for them.
-
-    This is needed to handle properly the case as follows:
-      - create temporary tables 'tmp1' and 'tmp2;
-      - create a merge table 'mrg1' from 'tmp1' and 'tmp2';
-      - create a stored routine (let's say a stored function),
-        which is using 'mrg1';
-      - prepare a statement that deals with the stored routine
-        (e.g. SELECT <stored function>).
-
-    So, the case might be like this:
-      CREATE TEMPORARY TABLE tmp1(a INT);
-      CREATE TEMPORARY TABLE tmp2(a INT);
-      CREATE TABLE mrg1(a INT) ENGINE=MERGE UNION=(tmp1, tmp2);
-      CREATE FUNCTION f1() RETURNS INT RETURN (SELECT COUNT(*) FROM mrg1);
-      PREPARE stmt1 FROM 'SELECT f1()';
-
-    What's going on is this:
-      - 'tables' are empty for the statement being prepared;
-      - thus, before the "big switch" no temporary table is opened;
-      - after 'f1' is opened, 'mrg1' is added to the prelocking list;
-      - after 'mrg1' is opened, 'tmp1' and 'tmp2' are added to 'tables';
-      - so, here we have not-opened temporary tables 'tmp1' and 'tmp2'
-        in the 'tables' list.
-
-    The thing is that HA_ATTACH_CHILDREN must be called for all merge
-    children during the prepare phase. This is critical because merge
-    children remembers "TABLE_SHARE ref type" and "TABLE_SHARE def version"
-    in the HA_ATTACH_CHILDREN operation.
-
-    If HA_ATTACH_CHILDREN is not called, these attributes are not set.
-    Then, during the first EXECUTE, those attributes need to be updated.
-    That would cause statement re-preparing (because changing those
-    attributes during EXECUTE is caught by THD::m_reprepare_observer).
-    The problem is that since those attributes are not set in merge children,
-    another round of PREPARE will not help. The attributes will be
-    remembered, but as soon as close_thread_tables() is called at the end
-    of PREPARE, this information will be lost again.
-  */
-
-  if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES)
-  {
-    List<TABLE_LIST> new_tl_arr;
-
-    for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global)
-    {
-      if (tl->table)
-        continue;
-
-      if (open_and_process_temporary_table(thd, tl))
-        goto error;
-
-      new_tl_arr.push_back(tl);
-    }
-
-    /*
-      Ensure that HA_ATTACH_CHILDREN has been called for newly added (by
-      prelocking) merge tables.
-    */
-    {
-      List_iterator_fast<TABLE_LIST> new_tl_arr_it(new_tl_arr);
-      TABLE_LIST *tl;
-      while ((tl= new_tl_arr_it++))
-      {
-        if (!tl->table ||
-            tl->table->file->ht->db_type != DB_TYPE_MRG_MYISAM)
-          continue;
-
-        /* MERGE tables need to access parent and child TABLE_LISTs. */
-        DBUG_ASSERT(tl->table->pos_in_table_list == tl);
-
-        if (tl->table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
-          goto error;
-      }
-    }
-  }
-
   if (res == 0)
     DBUG_RETURN(stmt->is_sql_prepare() ?
                 FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-11-30 08:30:48 +0000
+++ b/sql/sql_view.cc	2010-12-02 06:57:30 +0000
@@ -441,18 +441,6 @@ bool mysql_create_view(THD *thd, TABLE_L
     goto err;
   }
 
-  /*
-    Open matching temporary tables for table list elements added by
-    prelocking algorithm. We need this in order to catch cases when
-    view uses functions that use temporary tables (note that this
-    check is not robust).
-  */
-  if (open_and_process_temporary_table_list(thd, lex->query_tables))
-  {
-    res= TRUE;
-    goto err;
-  }
-
   view= lex->unlink_first_table(&link_to_local);
 
   if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))


Attachment: [text/bzr-bundle] bzr/dmitry.lenev@oracle.com-20101202065730-ayv1wvuz3eiopumr.bundle
Thread
bzr commit into mysql-trunk-bugfixing branch (Dmitry.Lenev:3394) Bug#27480Dmitry Lenev2 Dec