From: Dmitry Lenev Date: December 2 2010 7:00am Subject: bzr push into mysql-trunk-bugfixing branch (Dmitry.Lenev:3393 to 3394) Bug#27480 List-Archive: http://lists.mysql.com/commits/125744 X-Bug: 27480 Message-Id: <20101202070004.9BDC21E5228@mockturtle> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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 3393 Dmitry Lenev 2010-12-01 Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). Review fixes in progress. Fixed handling of administrative commands, extended test-coverage. modified: mysql-test/r/grant4.result mysql-test/t/grant4.test sql/sql_admin.cc sql/sql_parse.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 ). - - 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 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 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)) No bundle (reason: useless for push emails).