From: Alexander Nozdrin Date: October 27 2010 4:37pm Subject: bzr commit into mysql-5.5-bugteam branch (alexander.nozdrin:3102) Bug#27480 List-Archive: http://lists.mysql.com/commits/122136 X-Bug: 27480 Message-Id: <201010271638.o9RAkhqE029787@acsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5989403677333247201==" --===============5989403677333247201== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/alik/MySQL/bzr/00/bug27480/mysql-5.5-bugteam-open_tmp_table/ based on revid:georgi.kodinov@stripped 3102 Alexander Nozdrin 2010-10-27 Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege to allow temp table operations): - move opening of temporary tables out of open_table(); - make open_table() to work with base tables and views only. It will be renamed to open_base_table_or_view() in a follow-up patch. - introduce open_temporary_table() to open temporary tables (similar to open_table()); - introduce open_and_process_temporary_table() to fully prepare temporary tables for use (similar to open_and_process_table()); - introduce a new "command flag" (CF_PREOPEN_TMP_TABLES) to mark statements that work with temporary tables, thus temporary tables should be opened for those statements; - open temporary tables in a unified way in the beginning of the statements marked with CF_PREOPEN_TMP_TABLES flag; - introduce a new "command flag" (CF_HA_CLOSE) to mark statements for which open handlers (by HANDLER OPEN) should be closed; - close open handlers in a unified way in the beginning of the statements marked with CF_HA_CLOSE flag. modified: mysql-test/r/handler_myisam.result mysql-test/r/merge.result mysql-test/r/temp_table.result mysql-test/t/handler_myisam.test mysql-test/t/merge.test mysql-test/t/temp_table.test sql/sp_head.cc sql/sql_admin.cc sql/sql_base.cc sql/sql_base.h sql/sql_class.h sql/sql_handler.cc sql/sql_insert.cc sql/sql_parse.cc sql/sql_prepare.cc sql/sql_rename.cc sql/sql_show.cc sql/sql_table.cc sql/sql_truncate.cc sql/sql_view.cc === modified file 'mysql-test/r/handler_myisam.result' --- a/mysql-test/r/handler_myisam.result 2010-09-24 07:18:16 +0000 +++ b/mysql-test/r/handler_myisam.result 2010-10-27 16:36:56 +0000 @@ -1862,4 +1862,70 @@ a b 4 40 HANDLER t1 CLOSE; DROP TABLE t1; +# +# Bug#27480 +# +CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; +# -- CREATE TABLE +HANDLER t1 OPEN; +CREATE TABLE t2 SELECT * FROM t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +DROP TABLE t2; +# -- REPAIR TABLE +HANDLER t1 OPEN; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- ANALYZE TABLE +HANDLER t1 OPEN; +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- OPTIMIZE TABLE +HANDLER t1 OPEN; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- CHECK TABLE +HANDLER t1 OPEN; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- ALTER TABLE +HANDLER t1 OPEN; +ALTER TABLE t1 ADD COLUMN b INT; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- DROP TABLE +HANDLER t1 OPEN; +DROP TABLE t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +CREATE TEMPORARY TABLE t1(a INT, b INT, INDEX i(a)); +set global keycache1.key_cache_block_size=2048; +set global keycache1.key_buffer_size=1*1024*1024; +set global keycache1.key_buffer_size=1024*1024; +# -- CACHE INDEX +HANDLER t1 OPEN; +CACHE INDEX t1 IN keycache1; +Table Op Msg_type Msg_text +test.t1 assign_to_keycache status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- LOAD INDEX +HANDLER t1 OPEN; +LOAD INDEX INTO CACHE t1; +Table Op Msg_type Msg_text +test.t1 preload_keys status OK +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER End of 5.1 tests === modified file 'mysql-test/r/merge.result' --- a/mysql-test/r/merge.result 2010-10-06 07:56:29 +0000 +++ b/mysql-test/r/merge.result 2010-10-27 16:36:56 +0000 @@ -2716,10 +2716,7 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; CREATE TEMPORARY TABLE t1 (c1 INT); ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); OPTIMIZE TABLE t1; -Table Op Msg_type Msg_text -test.t1 optimize Error Table 'test.t_not_exists' doesn't exist -test.t1 optimize Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist -test.t1 optimize error Corrupt +ERROR HY000: Can't reopen table: 't1' DROP TABLE t1; # # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine === modified file 'mysql-test/r/temp_table.result' --- a/mysql-test/r/temp_table.result 2010-06-23 11:34:40 +0000 +++ b/mysql-test/r/temp_table.result 2010-10-27 16:36:56 +0000 @@ -223,3 +223,46 @@ CREATE TEMPORARY TABLE bug48067.t1 (c1 i DROP DATABASE bug48067; DROP TEMPORARY table bug48067.t1; End of 5.1 tests +CREATE TEMPORARY TABLE t1(a INT); +CREATE TEMPORARY TABLE t2(b INT); +CREATE TEMPORARY TABLE t3(c INT); +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); +ANALYZE TABLE t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +test.t3 analyze status OK +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); +CHECK TABLE t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +test.t3 check status OK +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); +CHECKSUM TABLE t1, t2, t3; +Table Checksum +test.t1 xxx +test.t2 xxx +test.t3 xxx +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); +OPTIMIZE TABLE t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 optimize status OK +test.t2 optimize status OK +test.t3 optimize status OK +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); +REPAIR TABLE t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 repair status OK +test.t2 repair status OK +test.t3 repair status OK === modified file 'mysql-test/t/handler_myisam.test' --- a/mysql-test/t/handler_myisam.test 2010-06-09 10:45:04 +0000 +++ b/mysql-test/t/handler_myisam.test 2010-10-27 16:36:56 +0000 @@ -97,4 +97,73 @@ HANDLER t1 CLOSE; DROP TABLE t1; +--echo # +--echo # Bug#27480 +--echo # + +CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; + +--echo # -- CREATE TABLE +HANDLER t1 OPEN; +CREATE TABLE t2 SELECT * FROM t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +DROP TABLE t2; + +--echo # -- REPAIR TABLE +HANDLER t1 OPEN; +REPAIR TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- ANALYZE TABLE +HANDLER t1 OPEN; +ANALYZE TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- OPTIMIZE TABLE +HANDLER t1 OPEN; +OPTIMIZE TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- CHECK TABLE +HANDLER t1 OPEN; +CHECK TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- ALTER TABLE +HANDLER t1 OPEN; +ALTER TABLE t1 ADD COLUMN b INT; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- DROP TABLE +HANDLER t1 OPEN; +DROP TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +CREATE TEMPORARY TABLE t1(a INT, b INT, INDEX i(a)); + +set global keycache1.key_cache_block_size=2048; +set global keycache1.key_buffer_size=1*1024*1024; +set global keycache1.key_buffer_size=1024*1024; + +--echo # -- CACHE INDEX +HANDLER t1 OPEN; +CACHE INDEX t1 IN keycache1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- LOAD INDEX +HANDLER t1 OPEN; +LOAD INDEX INTO CACHE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + + --echo End of 5.1 tests === modified file 'mysql-test/t/merge.test' --- a/mysql-test/t/merge.test 2010-10-06 07:56:29 +0000 +++ b/mysql-test/t/merge.test 2010-10-27 16:36:56 +0000 @@ -2195,6 +2195,7 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; --echo # CREATE TEMPORARY TABLE t1 (c1 INT); ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); +--error ER_CANT_REOPEN_TABLE OPTIMIZE TABLE t1; DROP TABLE t1; === modified file 'mysql-test/t/temp_table.test' --- a/mysql-test/t/temp_table.test 2010-06-23 11:34:40 +0000 +++ b/mysql-test/t/temp_table.test 2010-10-27 16:36:56 +0000 @@ -251,3 +251,40 @@ DROP DATABASE bug48067; DROP TEMPORARY table bug48067.t1; --echo End of 5.1 tests + +# Check admin statements. + +CREATE TEMPORARY TABLE t1(a INT); +CREATE TEMPORARY TABLE t2(b INT); +CREATE TEMPORARY TABLE t3(c INT); + +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); + +ANALYZE TABLE t1, t2, t3; + +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); + +CHECK TABLE t1, t2, t3; + +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); + +--replace_column 2 xxx +CHECKSUM TABLE t1, t2, t3; + +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); + +OPTIMIZE TABLE t1, t2, t3; + +INSERT INTO t1 VALUES (1), (2), (3); +INSERT INTO t2 VALUES (11), (12), (13); +INSERT INTO t3 VALUES (101), (102), (103); + +REPAIR TABLE t1, t2, t3; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2010-10-27 07:32:26 +0000 +++ b/sql/sp_head.cc 2010-10-27 16:36:56 +0000 @@ -2950,6 +2950,9 @@ sp_lex_keeper::reset_lex_and_exec_core(T reinit_stmt_before_use(thd, m_lex); if (open_tables) + res= open_and_process_temporary_table_list(thd, m_lex->query_tables); + + if (!res && open_tables) res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables); if (!res) @@ -4169,6 +4172,11 @@ 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_admin.cc' --- a/sql/sql_admin.cc 2010-09-22 08:15:41 +0000 +++ b/sql/sql_admin.cc 2010-10-27 16:36:56 +0000 @@ -88,8 +88,7 @@ static int prepare_for_repair(THD *thd, MDL_EXCLUSIVE); if (lock_table_names(thd, table_list, table_list->next_global, - thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) + thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(0); has_mdl_lock= TRUE; @@ -262,6 +261,8 @@ static bool mysql_admin_table(THD* thd, HA_CHECK_OPT* check_opt, const char *operator_name, thr_lock_type lock_type, + bool any_priv_will_do, + ulong op_privs, bool open_for_modify, bool no_warnings_for_error, uint extra_open_options, @@ -292,8 +293,6 @@ static bool mysql_admin_table(THD* thd, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - mysql_ha_rm_tables(thd, tables); - for (table= tables; table; table= table->next_local) { char table_name[NAME_LEN*2+2]; @@ -301,6 +300,29 @@ static bool mysql_admin_table(THD* thd, bool fatal_error=0; bool open_error; + /* + Here we need to open list of tables (one table is not enough) because + of merge tables: children of merge tables must be opened here. + */ + + TABLE_LIST *next_global_tl= table->next_global; + + if (open_and_process_temporary_table_list(thd, table)) + DBUG_RETURN(TRUE); + + TABLE_LIST *last_added_tl; + + for (last_added_tl= table; + last_added_tl && last_added_tl->next_global != next_global_tl; + last_added_tl= last_added_tl->next_global) + ; + + if (op_privs) + { + if (check_table_access(thd, op_privs, table, any_priv_will_do, 1, FALSE)) + DBUG_RETURN(TRUE); + } + DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name)); DBUG_PRINT("admin", ("extra_open_options: %u", extra_open_options)); strxmov(table_name, db, ".", table->table_name, NullS); @@ -316,11 +338,10 @@ static bool mysql_admin_table(THD* thd, MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ); /* open only one table from local list of command */ { - TABLE_LIST *save_next_global, *save_next_local; - save_next_global= table->next_global; - table->next_global= 0; - save_next_local= table->next_local; - table->next_local= 0; + TABLE_LIST *next_global_saved= last_added_tl->next_global; + TABLE_LIST *next_local_saved= last_added_tl->next_local; + last_added_tl->next_global= NULL; + last_added_tl->next_local= NULL; select->table_list.first= table; /* Time zone tables and SP tables can be add to lex->query_tables list, @@ -343,71 +364,71 @@ static bool mysql_admin_table(THD* thd, open_error= open_and_lock_tables(thd, table, TRUE, 0); thd->no_warnings_for_error= 0; - table->next_global= save_next_global; - table->next_local= save_next_local; + last_added_tl->next_global= next_global_saved; + last_added_tl->next_local= next_local_saved; thd->open_options&= ~extra_open_options; + } - /* - If open_and_lock_tables() failed, close_thread_tables() will close - the table and table->table can therefore be invalid. - */ - if (open_error) - table->table= NULL; + /* + If open_and_lock_tables() failed, close_thread_tables() will close + the table and table->table can therefore be invalid. + */ + if (open_error) + table->table= NULL; + /* + Under locked tables, we know that the table can be opened, + so any errors opening the table are logical errors. + In these cases it does not make sense to try to repair. + */ + if (open_error && thd->locked_tables_mode) + { + result_code= HA_ADMIN_FAILED; + goto send_result; + } +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (table->table) + { /* - Under locked tables, we know that the table can be opened, - so any errors opening the table are logical errors. - In these cases it does not make sense to try to repair. + Set up which partitions that should be processed + if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION .. + CACHE INDEX/LOAD INDEX for specified partitions */ - if (open_error && thd->locked_tables_mode) - { - result_code= HA_ADMIN_FAILED; - goto send_result; - } -#ifdef WITH_PARTITION_STORAGE_ENGINE - if (table->table) - { - /* - Set up which partitions that should be processed - if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION .. - CACHE INDEX/LOAD INDEX for specified partitions - */ - Alter_info *alter_info= &lex->alter_info; + Alter_info *alter_info= &lex->alter_info; - if (alter_info->flags & ALTER_ADMIN_PARTITION) + if (alter_info->flags & ALTER_ADMIN_PARTITION) + { + if (!table->table->part_info) { - if (!table->table->part_info) - { - my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); - DBUG_RETURN(TRUE); - } - uint num_parts_found; - uint num_parts_opt= alter_info->partition_names.elements; - num_parts_found= set_part_state(alter_info, table->table->part_info, - PART_ADMIN); - if (num_parts_found != num_parts_opt && - (!(alter_info->flags & ALTER_ALL_PARTITION))) - { - char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; - size_t length; - DBUG_PRINT("admin", ("sending non existent partition error")); - protocol->prepare_for_resend(); - protocol->store(table_name, system_charset_info); - protocol->store(operator_name, system_charset_info); - protocol->store(STRING_WITH_LEN("error"), system_charset_info); - length= my_snprintf(buff, sizeof(buff), - ER(ER_DROP_PARTITION_NON_EXISTENT), - table_name); - protocol->store(buff, length, system_charset_info); - if(protocol->write()) - goto err; - my_eof(thd); + my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); + DBUG_RETURN(TRUE); + } + uint num_parts_found; + uint num_parts_opt= alter_info->partition_names.elements; + num_parts_found= set_part_state(alter_info, table->table->part_info, + PART_ADMIN); + if (num_parts_found != num_parts_opt && + (!(alter_info->flags & ALTER_ALL_PARTITION))) + { + char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; + size_t length; + DBUG_PRINT("admin", ("sending non existent partition error")); + protocol->prepare_for_resend(); + protocol->store(table_name, system_charset_info); + protocol->store(operator_name, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + length= my_snprintf(buff, sizeof(buff), + ER(ER_DROP_PARTITION_NON_EXISTENT), + table_name); + protocol->store(buff, length, system_charset_info); + if(protocol->write()) goto err; - } + my_eof(thd); + goto err; } } -#endif } +#endif DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table)); if (prepare_func) @@ -560,6 +581,15 @@ static bool mysql_admin_table(THD* thd, trans_rollback(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); + + /* + table_list->table has been closed and freed. Do not reference + uninitialized data. open_tables() could fail. + */ + table->table= NULL; + /* Same applies to MDL ticket. */ + table->mdl_request.ticket= NULL; + tmp_disable_binlog(thd); // binlogging is done by caller if wanted result_code= mysql_recreate_table(thd, table); reenable_binlog(thd); @@ -678,6 +708,15 @@ send_result_message: trans_commit(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); + + /* + table_list->table has been closed and freed. Do not reference + uninitialized data. open_tables() could fail. + */ + table->table= NULL; + /* Same applies to MDL ticket. */ + table->mdl_request.ticket= NULL; + DEBUG_SYNC(thd, "ha_admin_try_alter"); protocol->store(STRING_WITH_LEN("note"), system_charset_info); protocol->store(STRING_WITH_LEN( @@ -704,8 +743,8 @@ send_result_message: trans_commit(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); - table->table= NULL; - if (!result_code) // recreation went ok + if (!result_code && // recreation went ok + !table->table) // not a temporary table opened above { /* Clear the ticket released above. */ table->mdl_request.ticket= NULL; @@ -818,7 +857,6 @@ send_result_message: trans_commit_implicit(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); - /* If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run separate open_tables() for each CHECK TABLE argument. @@ -847,8 +885,6 @@ err: trans_rollback(thd); close_thread_tables(thd); // Shouldn't be needed thd->mdl_context.release_transactional_locks(); - if (table) - table->table=0; DBUG_RETURN(TRUE); } @@ -884,8 +920,10 @@ bool mysql_assign_to_keycache(THD* thd, mysql_mutex_unlock(&LOCK_global_system_variables); check_opt.key_cache= key_cache; DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt, - "assign_to_keycache", TL_READ_NO_INSERT, 0, 0, - 0, 0, &handler::assign_to_keycache, 0)); + "assign_to_keycache", TL_READ_NO_INSERT, + FALSE, 0, + FALSE, FALSE, 0, NULL, + &handler::assign_to_keycache, NULL)); } @@ -911,8 +949,10 @@ bool mysql_preload_keys(THD* thd, TABLE_ outdated information if parallel inserts into cache blocks happen. */ DBUG_RETURN(mysql_admin_table(thd, tables, 0, - "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0, - &handler::preload_keys, 0)); + "preload_keys", TL_READ_NO_INSERT, + FALSE, 0, + FALSE, FALSE, 0, NULL, + &handler::preload_keys, NULL)); } @@ -923,13 +963,11 @@ bool Analyze_table_statement::execute(TH thr_lock_type lock_type = TL_READ_NO_INSERT; DBUG_ENTER("Analyze_table_statement::execute"); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, - FALSE, UINT_MAX, FALSE)) - goto error; thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &m_lex->check_opt, - "analyze", lock_type, 1, 0, 0, 0, - &handler::ha_analyze, 0); + "analyze", lock_type, + FALSE, SELECT_ACL | INSERT_ACL, + TRUE, FALSE, 0, NULL, &handler::ha_analyze, NULL); /* ! we write after unlocking the table */ if (!res && !m_lex->no_write_to_binlog) { @@ -941,7 +979,6 @@ bool Analyze_table_statement::execute(TH m_lex->select_lex.table_list.first= first_table; m_lex->query_tables= first_table; -error: DBUG_RETURN(res); } @@ -959,7 +996,9 @@ bool Check_table_statement::execute(THD thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check", - lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, + lock_type, + TRUE, SELECT_ACL, + FALSE, FALSE, HA_OPEN_FOR_REPAIR, NULL, &handler::ha_check, &view_checksum); m_lex->select_lex.table_list.first= first_table; @@ -983,8 +1022,9 @@ bool Optimize_table_statement::execute(T res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? mysql_recreate_table(thd, first_table) : mysql_admin_table(thd, first_table, &m_lex->check_opt, - "optimize", TL_WRITE, 1, 0, 0, 0, - &handler::ha_optimize, 0); + "optimize", TL_WRITE, + FALSE, SELECT_ACL | INSERT_ACL, + TRUE, FALSE, 0, NULL, &handler::ha_optimize, 0); /* ! we write after unlocking the table */ if (!res && !m_lex->no_write_to_binlog) { @@ -1012,10 +1052,12 @@ bool Repair_table_statement::execute(THD goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", - TL_WRITE, 1, + TL_WRITE, + FALSE, SELECT_ACL| INSERT_ACL, + TRUE, test(m_lex->check_opt.sql_flags & TT_USEFRM), HA_OPEN_FOR_REPAIR, &prepare_for_repair, - &handler::ha_repair, 0); + &handler::ha_repair, NULL); /* ! we write after unlocking the table */ if (!res && !m_lex->no_write_to_binlog) === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2010-10-14 16:56:56 +0000 +++ b/sql/sql_base.cc 2010-10-27 16:36:56 +0000 @@ -2563,46 +2563,42 @@ tdc_wait_for_old_version(THD *thd, const } -/* - Open a table. +/** + Open a base table. - SYNOPSIS - open_table() - thd Thread context. - table_list Open first table in list. - action INOUT Pointer to variable of enum_open_table_action type + @param thd Thread context. + @param table_list Open first table in list. + @param action[in,out] Pointer to variable of enum_open_table_action type which will be set according to action which is required to remedy problem appeared during attempt to open table. - flags Bitmap of flags to modify how open works: - MYSQL_OPEN_IGNORE_FLUSH - Open table even if - someone has done a flush or there is a pending - exclusive metadata lock requests against it - (i.e. request high priority metadata lock). - No version number checking is done. - MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary - table not the base table or view. - MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable - metadata lock for tables on which we are going to - take some kind of write table-level lock. - - IMPLEMENTATION - Uses a cache of open tables to find a table not in use. - - If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened - only if it exists. If the open strategy is OPEN_STUB, the underlying table - is never opened. In both cases, metadata locks are always taken according - to the lock strategy. - - RETURN - TRUE Open failed. "action" parameter may contain type of action - needed to remedy problem before retrying again. - FALSE Success. Members of TABLE_LIST structure are filled properly (e.g. - TABLE_LIST::table is set for real tables and TABLE_LIST::view is - set for views). + @param flags Bitmap of flags to modify how open works: + MYSQL_OPEN_IGNORE_FLUSH - Open table even if + someone has done a flush or there is a pending + exclusive metadata lock requests against it (i.e. + request high priority metadata lock). No version + number checking is done. + MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable + metadata lock for tables on which we are going to + take some kind of write table-level lock. + + Uses a cache of open tables to find a TABLE instance not in use. + + If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is + opened only if it exists. If the open strategy is OPEN_STUB, the + underlying table is never opened. In both cases, metadata locks are + always taken according to the lock strategy. + + The function used to open temporary tables, but now it opens base tables + only. + + @retval TRUE Open failed. "action" parameter may contain type of action + needed to remedy problem before retrying again. + @retval FALSE Success. Members of TABLE_LIST structure are filled properly + (e.g. TABLE_LIST::table is set for real tables and + TABLE_LIST::view is set for views). */ - bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, Open_table_context *ot_ctx) { @@ -2617,6 +2613,14 @@ bool open_table(THD *thd, TABLE_LIST *ta my_hash_value_type hash_value; DBUG_ENTER("open_table"); + /* + The table must not be opened already. The table can be pre-opened for + some statements if it is a temporary table. + + open_temporary_table() must be used to open temporary tables. + */ + DBUG_ASSERT(!table_list->table); + /* an open table operation needs a lot of the stack space */ if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias)) DBUG_RETURN(TRUE); @@ -2628,11 +2632,10 @@ bool open_table(THD *thd, TABLE_LIST *ta TMP_TABLE_KEY_EXTRA); /* - We need this to work for all tables, including temporary - tables, for backwards compatibility. But not under LOCK - TABLES, since under LOCK TABLES one can't use a non-prelocked - table. This code only works for updates done inside DO/SELECT - f1() statements, normal DML is handled by means of + We need this to work for all tables, for backwards compatibility. + But not under LOCK TABLES, since under LOCK TABLES one can't use a + non-prelocked table. This code only works for updates done inside + DO/SELECT f1() statements, normal DML is handled by means of sql_command_flags. */ if (global_read_lock && table_list->lock_type >= TL_WRITE_ALLOW_WRITE && @@ -2653,63 +2656,12 @@ bool open_table(THD *thd, TABLE_LIST *ta DBUG_RETURN(TRUE); } } - /* - Unless requested otherwise, try to resolve this table in the list - of temporary tables of this thread. In MySQL temporary tables - are always thread-local and "shadow" possible base tables with the - same name. This block implements the behaviour. - TODO: move this block into a separate function. - */ - if (table_list->open_type != OT_BASE_ONLY && - ! (flags & MYSQL_OPEN_SKIP_TEMPORARY)) - { - for (table= thd->temporary_tables; table ; table=table->next) - { - if (table->s->table_cache_key.length == key_length + - TMP_TABLE_KEY_EXTRA && - !memcmp(table->s->table_cache_key.str, key, - key_length + TMP_TABLE_KEY_EXTRA)) - { - /* - We're trying to use the same temporary table twice in a query. - Right now we don't support this because a temporary table - is always represented by only one TABLE object in THD, and - it can not be cloned. Emit an error for an unsupported behaviour. - */ - if (table->query_id) - { - DBUG_PRINT("error", - ("query_id: %lu server_id: %u pseudo_thread_id: %lu", - (ulong) table->query_id, (uint) thd->server_id, - (ulong) thd->variables.pseudo_thread_id)); - my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); - DBUG_RETURN(TRUE); - } - table->query_id= thd->query_id; - thd->thread_specific_used= TRUE; - DBUG_PRINT("info",("Using temporary table")); - goto reset; - } - } - } - - if (table_list->open_type == OT_TEMPORARY_ONLY || - (flags & MYSQL_OPEN_TEMPORARY_ONLY)) - { - if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL) - { - my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name); - DBUG_RETURN(TRUE); - } - else - DBUG_RETURN(FALSE); - } /* - The table is not temporary - if we're in pre-locked or LOCK TABLES - mode, let's try to find the requested table in the list of pre-opened - and locked tables. If the table is not there, return an error - we can't - open not pre-opened tables in pre-locked/LOCK TABLES mode. + If we're in pre-locked or LOCK TABLES mode, let's try to find the + requested table in the list of pre-opened and locked tables. If the + table is not there, return an error - we can't open not pre-opened + tables in pre-locked/LOCK TABLES mode. TODO: move this block into a separate function. */ if (thd->locked_tables_mode && @@ -2768,6 +2720,7 @@ bool open_table(THD *thd, TABLE_LIST *ta DBUG_PRINT("info",("Using locked table")); goto reset; } + /* Is this table a view and not a base table? (it is work around to allow to open view with locked tables, @@ -2805,7 +2758,7 @@ bool open_table(THD *thd, TABLE_LIST *ta } /* No table in the locked tables list. In case of explicit LOCK TABLES - this can happen if a user did not include the able into the list. + this can happen if a user did not include the table into the list. In case of pre-locked mode locked tables list is generated automatically, so we may only end up here if the table did not exist when locked tables list was created. @@ -2817,10 +2770,7 @@ bool open_table(THD *thd, TABLE_LIST *ta DBUG_RETURN(TRUE); } - /* - Non pre-locked/LOCK TABLES mode, and the table is not temporary. - This is the normal use case. - */ + /* Non pre-locked/LOCK TABLES mode. This is the normal use case. */ if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK)) { @@ -3976,8 +3926,7 @@ recover_from_failed_open(THD *thd) case OT_DISCOVER: { if ((result= lock_table_names(thd, m_failed_table, NULL, - get_timeout(), - MYSQL_OPEN_SKIP_TEMPORARY))) + get_timeout(), 0))) break; tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, @@ -3993,8 +3942,7 @@ recover_from_failed_open(THD *thd) case OT_REPAIR: { if ((result= lock_table_names(thd, m_failed_table, NULL, - get_timeout(), - MYSQL_OPEN_SKIP_TEMPORARY))) + get_timeout(), 0))) break; tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, @@ -4316,6 +4264,25 @@ open_and_process_table(THD *thd, LEX *le error= TRUE; goto end; } + + /* + If this TABLE_LIST object has an associated open TABLE object + (TABLE_LIST::table is not NULL), that TABLE object must be a pre-opened + temporary table. + */ + if (tables->table) + { + DBUG_ASSERT(is_temporary_table(tables->table)); + DBUG_RETURN(FALSE); + } + + /* + If we're in CREATE TEMPORARY TABLE statement, we should not proceed + to the actual opening. + */ + if (tables->open_type == OT_TEMPORARY_ONLY) + DBUG_RETURN(FALSE); + DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: %p", tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here (*counter)++; @@ -4325,6 +4292,26 @@ 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. 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. + */ + DBUG_RETURN(FALSE); + } + + 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. @@ -4426,6 +4413,7 @@ open_and_process_table(THD *thd, LEX *le goto end; } + /* Set appropriate TABLE::lock_type. */ if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode) { if (tables->lock_type == TL_WRITE_DEFAULT) @@ -4436,6 +4424,8 @@ open_and_process_table(THD *thd, LEX *le else tables->table->reginfo.lock_type= tables->lock_type; } + + /* Copy grant information from TABLE_LIST instance to TABLE one. */ tables->table->grant= tables->grant; /* Check and update metadata version of a base table. */ @@ -4523,18 +4513,17 @@ lock_table_names(THD *thd, for (table= tables_start; table && table != tables_end; table= table->next_global) { - if (table->mdl_request.type >= MDL_SHARED_NO_WRITE && - !(table->open_type == OT_TEMPORARY_ONLY || - (flags & MYSQL_OPEN_TEMPORARY_ONLY) || - (table->open_type != OT_BASE_ONLY && - ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) && - find_temporary_table(thd, table)))) + if (table->mdl_request.type < MDL_SHARED_NO_WRITE || + table->open_type == OT_TEMPORARY_ONLY || + (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table))) { - if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && - schema_set.insert(table)) - return TRUE; - mdl_requests.push_front(&table->mdl_request); + continue; } + + if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && schema_set.insert(table)) + return TRUE; + + mdl_requests.push_front(&table->mdl_request); } if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && @@ -4593,35 +4582,34 @@ open_tables_check_upgradable_mdl(THD *th for (table= tables_start; table && table != tables_end; table= table->next_global) { - if (table->mdl_request.type >= MDL_SHARED_NO_WRITE && - !(table->open_type == OT_TEMPORARY_ONLY || - (flags & MYSQL_OPEN_TEMPORARY_ONLY) || - (table->open_type != OT_BASE_ONLY && - ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) && - find_temporary_table(thd, table)))) + if (table->mdl_request.type < MDL_SHARED_NO_WRITE || + table->open_type == OT_TEMPORARY_ONLY || + (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table))) { - /* - We don't need to do anything about the found TABLE instance as it - will be handled later in open_tables(), we only need to check that - an upgradable lock is already acquired. When we enter LOCK TABLES - mode, SNRW locks are acquired before all other locks. So if under - LOCK TABLES we find that there is TABLE instance with upgradeable - lock, all other instances of TABLE for the same table will have the - same ticket. - - Note that this works OK even for CREATE TABLE statements which - request X type of metadata lock. This is because under LOCK TABLES - such statements don't create the table but only check if it exists - or, in most complex case, only insert into it. - Thus SNRW lock should be enough. - - Note that find_table_for_mdl_upgrade() will report an error if - no suitable ticket is found. - */ - if (!find_table_for_mdl_upgrade(thd->open_tables, table->db, - table->table_name, FALSE)) - return TRUE; + continue; } + + /* + We don't need to do anything about the found TABLE instance as it + will be handled later in open_tables(), we only need to check that + an upgradable lock is already acquired. When we enter LOCK TABLES + mode, SNRW locks are acquired before all other locks. So if under + LOCK TABLES we find that there is TABLE instance with upgradeable + lock, all other instances of TABLE for the same table will have the + same ticket. + + Note that this works OK even for CREATE TABLE statements which + request X type of metadata lock. This is because under LOCK TABLES + such statements don't create the table but only check if it exists + or, in most complex case, only insert into it. + Thus SNRW lock should be enough. + + Note that find_table_for_mdl_upgrade() will report an error if + no suitable ticket is found. + */ + if (!find_table_for_mdl_upgrade(thd->open_tables, table->db, + table->table_name, FALSE)) + return TRUE; } return FALSE; @@ -4800,6 +4788,10 @@ restart: if (ot_ctx.recover_from_failed_open(thd)) goto err; + /* Re-open temporary tables after close_tables_for_reopen(). */ + if (open_and_process_temporary_table_list(thd, *start)) + goto err; + error= FALSE; goto restart; } @@ -4846,6 +4838,10 @@ restart: if (ot_ctx.recover_from_failed_open(thd)) goto err; + /* Re-open temporary tables after close_tables_for_reopen(). */ + if (open_and_process_temporary_table_list(thd, *start)) + goto err; + error= FALSE; goto restart; } @@ -4876,6 +4872,11 @@ restart: { TABLE *tbl= tables->table; + /* + NOTE: temporary merge tables should be processed here too, because + a temporary merge table can be based on non-temporary tables. + */ + /* Schema tables may not have a TABLE object here. */ if (tbl && tbl->file->ht->db_type == DB_TYPE_MRG_MYISAM) { @@ -5893,6 +5894,153 @@ static void update_field_dependencies(TH } +/** + Find a temporary table specified by TABLE_LIST instance in the cache and + prepare its TABLE instance for use. + + This function tries to resolve this table in the list of temporary tables + of this thread. Temporary tables are thread-local and "shadow" base + tables with the same name. + + open_temporary_table() should be considered as an internal function. + Usually, open_and_process_temporary_table() should be used instead to + open temporary table completely. The only case where + open_temporary_table() is used directly is implementation of INSERT INTO + statement (sql_insert.cc). + + Note: we used to check global_read_lock before opening temporary tables. + However, that limitation was artificial and is removed now. + + @return Error status. + @retval FALSE On success. If a temporary table exists for the given + key, tl->table is set. + @retval TRUE On error. my_error() has been called. +*/ + +bool open_temporary_table(THD *thd, TABLE_LIST *tl) +{ + DBUG_ENTER("open_temporary_table"); + DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name)); + + if (tl->open_type == OT_BASE_ONLY) + { + DBUG_PRINT("info", ("skip_temporary is set")); + + tl->table= NULL; + DBUG_RETURN(FALSE); + } + + char table_key[MAX_DBKEY_LENGTH]; + uint table_key_length= create_table_def_key(thd, table_key, tl, 1); + + TABLE *table= find_temporary_table(thd, table_key, table_key_length); + + if (!table) + { + tl->table= NULL; + DBUG_RETURN(FALSE); + } + + if (table->query_id) + { + /* + We're trying to use the same temporary table twice in a query. + Right now we don't support this because a temporary table is always + represented by only one TABLE object in THD, and it can not be + cloned. Emit an error for an unsupported behaviour. + */ + + DBUG_PRINT("error", + ("query_id: %lu server_id: %u pseudo_thread_id: %lu", + (ulong) table->query_id, (uint) thd->server_id, + (ulong) thd->variables.pseudo_thread_id)); + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + DBUG_RETURN(TRUE); + } + + table->query_id= thd->query_id; + thd->thread_specific_used= TRUE; + + tl->updatable= 1; // It is not derived table nor non-updatable VIEW. + tl->table= table; + + table->init(thd, tl); + + DBUG_PRINT("info", ("Using temporary table")); + DBUG_RETURN(FALSE); +} + + +bool open_and_process_temporary_table_list(THD *thd, TABLE_LIST *tl_list) +{ + DBUG_ENTER("open_and_process_temporary_table_list"); + + for (TABLE_LIST *tl= tl_list; tl; tl= tl->next_global) + { + if (open_and_process_temporary_table(thd, tl)) + DBUG_RETURN(TRUE); + } + + DBUG_RETURN(FALSE); +} + + +/** + Open a temporary table specified by TABLE_LIST instance. + + @return Error status. + @retval FALSE On success. Opened temporary table is returned in + TABLE_LIST::table member. If TABLE_LIST::table is NULL, + the specified temporary table does not exist. + @retval TRUE On error. my_error() has been called. +*/ + +bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl) +{ + DBUG_ENTER("open_and_process_temporary_table"); + + if (tl->schema_table || tl->derived) + DBUG_RETURN(FALSE); + + if (tl->table) + DBUG_RETURN(FALSE); // The table is already open. + + if (open_temporary_table(thd, tl)) + DBUG_RETURN(TRUE); + + /* + If 'tl->table' is NULL, that means there is no temporary table for the + table specified by 'tl'. This is not an error. + */ + if (!tl->table) + DBUG_RETURN(FALSE); + + /* Set appropriate TABLE::lock_type. */ + if (tl->lock_type != TL_UNLOCK && !thd->locked_tables_mode) + { + if (tl->lock_type == TL_WRITE_DEFAULT) + tl->table->reginfo.lock_type= thd->update_lock_default; + else if (tl->lock_type == TL_READ_DEFAULT) + tl->table->reginfo.lock_type= read_lock_type_for_table(thd, thd->lex, tl); + else + tl->table->reginfo.lock_type= tl->lock_type; + } + + /* Check and update metadata version of a base table. */ + if (check_and_update_table_version(thd, tl, tl->table->s)) + DBUG_RETURN(TRUE); + + /* MERGE tables need to access parent and child TABLE_LISTs. */ + DBUG_ASSERT(tl->table->pos_in_table_list == tl); + + /* Non-MERGE tables ignore this call. */ + if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST)) + DBUG_RETURN(TRUE); + + DBUG_RETURN(FALSE); +} + + /* Find a field by name in a view that uses merge algorithm. === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2010-09-30 13:29:12 +0000 +++ b/sql/sql_base.h 2010-10-27 16:36:56 +0000 @@ -93,7 +93,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST /* mysql_lock_tables() and open_table() flags bits */ #define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_OPEN_IGNORE_FLUSH 0x0002 -#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004 +/* MYSQL_OPEN_TEMPORARY_ONLY (0x0004) is not used anymore. */ #define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008 #define MYSQL_LOCK_LOG_TABLE 0x0010 /** @@ -106,8 +106,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST a new instance of the table. */ #define MYSQL_OPEN_GET_NEW_TABLE 0x0040 -/** Don't look up the table in the list of temporary tables. */ -#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080 +/* 0x0080 used to be MYSQL_OPEN_SKIP_TEMPORARY */ /** Fail instead of waiting when conficting metadata lock is discovered. */ #define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100 /** Open tables using MDL_SHARED lock instead of one specified in parser. */ @@ -134,7 +133,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\ MYSQL_LOCK_IGNORE_TIMEOUT |\ MYSQL_OPEN_GET_NEW_TABLE |\ - MYSQL_OPEN_SKIP_TEMPORARY |\ MYSQL_OPEN_HAS_MDL_LOCK) bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, @@ -263,6 +261,9 @@ void close_temporary_table(THD *thd, TAB void close_temporary(TABLE *table, bool free_share, bool delete_table); bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db, const char *table_name); +bool open_and_process_temporary_table_list(THD *thd, TABLE_LIST *tl_list); +bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl); +bool open_temporary_table(THD *thd, TABLE_LIST *tl); bool is_equal(const LEX_STRING *a, const LEX_STRING *b); /* Functions to work with system tables. */ @@ -546,6 +547,31 @@ private: /** + Indicate if a TABLE instance represents a temporary table. +*/ + +inline bool is_temporary_table(TABLE *table) +{ + /* + NOTE: 'table->s' might be NULL for specially constructed TABLE_LIST + instances, like for SHOW TRIGGERS LIKE ... + */ + + return table->s && table->s->tmp_table != NO_TMP_TABLE; +} + + +/** + Indicate if a TABLE_LIST instance represents a temporary table. +*/ + +inline bool is_temporary_table(TABLE_LIST *tl) +{ + return tl->table ? is_temporary_table(tl->table) : FALSE; +} + + +/** This internal handler is used to trap ER_NO_SUCH_TABLE. */ === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2010-10-23 13:09:27 +0000 +++ b/sql/sql_class.h 2010-10-27 16:36:56 +0000 @@ -3512,6 +3512,18 @@ public: */ #define CF_CAN_GENERATE_ROW_EVENTS (1U << 11) +/** + Identifies statements which may deal with temporary tables and for which + temporary tables should be pre-opened to simplify privilege checks. +*/ +#define CF_PREOPEN_TMP_TABLES (1U << 12) + +/** + Identfies statements for which open handlers should be closed in the + beginning of the statement. +*/ +#define CF_HA_CLOSE (1U << 13) + /* Bits in server_command_flags */ /** === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2010-08-12 13:50:23 +0000 +++ b/sql/sql_handler.cc 2010-10-27 16:36:56 +0000 @@ -285,12 +285,13 @@ bool mysql_ha_open(THD *thd, TABLE_LIST */ DBUG_ASSERT(! hash_tables->table); - /* - We use open_tables() here, rather than, say, - open_ltable() or open_table() because we would like to be able - to open a temporary table. - */ - error= open_tables(thd, &hash_tables, &counter, 0); + error= open_and_process_temporary_table(thd, hash_tables); + + if (is_temporary_table(hash_tables)) + hash_tables->table->grant= hash_tables->grant; + + if (!error && !hash_tables->table) + error= open_tables(thd, &hash_tables, &counter, 0); if (! error && ! (hash_tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER)) === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2010-10-07 10:01:51 +0000 +++ b/sql/sql_insert.cc 2010-10-27 16:36:56 +0000 @@ -3774,8 +3774,7 @@ static TABLE *create_table_from_items(TH } else { - Open_table_context ot_ctx(thd, MYSQL_OPEN_TEMPORARY_ONLY); - if (open_table(thd, create_table, thd->mem_root, &ot_ctx)) + if (open_temporary_table(thd, create_table)) { /* This shouldn't happen as creation of temporary table should make @@ -3785,7 +3784,9 @@ static TABLE *create_table_from_items(TH drop_temporary_table(thd, create_table, NULL); } else + { table= create_table->table; + } } } if (!table) // open failed === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-10-23 13:09:27 +0000 +++ b/sql/sql_parse.cc 2010-10-27 16:36:56 +0000 @@ -26,7 +26,7 @@ // start_waiting_global_read_lock, // lock_global_read_lock, // make_global_read_lock_block_commit -#include "sql_base.h" // find_temporary_tablesx +#include "sql_base.h" // find_temporary_table #include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_* #include "sql_show.h" // mysqld_list_*, mysqld_show_*, // calc_sum_of_all_status @@ -46,7 +46,6 @@ #include "sql_table.h" // mysql_create_like_table, // mysql_create_table, // mysql_alter_table, - // mysql_recreate_table, // mysql_backup_table, // mysql_restore_table #include "sql_reload.h" // reload_acl_and_cache @@ -285,8 +284,6 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL | @@ -344,7 +341,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; @@ -417,6 +414,53 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; + + /* + The following statements can deal with temporary tables, + so temporary tables should be pre-opened for those statements to + simplify privilege checking. + + There are other statements that deal with temporary tables and open + them, but which are not listed here. The thing is that the order of + pre-opening temporary tables for those statements is somewhat custom. + */ + + sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_LOAD]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DROP_INDEX]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_UPDATE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_INSERT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_REPLACE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES; + + /* + DDL statements should start with closing opened handlers. + */ + + sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_OPTIMIZE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ANALYZE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CHECK]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CREATE_INDEX]= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_INDEX]= CF_HA_CLOSE; + sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_HA_CLOSE; } bool sqlcom_can_generate_row_events(const THD *thd) @@ -1151,6 +1195,9 @@ bool dispatch_command(enum enum_server_c thd->set_query(fields, query_length); general_log_print(thd, command, "%s %s", table_list.table_name, fields); + if (open_and_process_temporary_table(thd, &table_list)) + break; + if (check_table_access(thd, SELECT_ACL, &table_list, TRUE, UINT_MAX, FALSE)) break; @@ -1989,6 +2036,15 @@ mysql_execute_command(THD *thd) DEBUG_SYNC(thd,"before_execute_sql_command"); #endif + if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE) + mysql_ha_rm_tables(thd, all_tables); + + if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) + { + if (open_and_process_temporary_table_list(thd, all_tables)) + goto error; + } + switch (lex->sql_command) { case SQLCOM_SHOW_EVENTS: @@ -2065,7 +2121,7 @@ mysql_execute_command(THD *thd) res= execute_sqlcom_select(thd, all_tables); break; } -case SQLCOM_PREPARE: + case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); break; @@ -2293,9 +2349,20 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + if (lex->create_info.merge_list.elements) + { + if (open_and_process_temporary_table_list( + thd, lex->create_info.merge_list.first)) + { + res= 1; + goto end_with_restore_list; + } + } + if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; + /* Might have been updated in create_table_precheck */ create_info.alias= create_table->alias; @@ -2347,9 +2414,6 @@ case SQLCOM_PREPARE: } #endif - /* Close any open handlers for the table. */ - mysql_ha_rm_tables(thd, create_table); - if (select_lex->item_list.elements) // With select { select_result *result; @@ -2507,6 +2571,7 @@ end_with_restore_list: goto error; DBUG_ASSERT(first_table == all_tables && first_table != 0); + if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ /* @@ -2651,6 +2716,13 @@ end_with_restore_list: else { /* + Temporary tables should be opened for SHOW CREATE TABLE, but not + for SHOW CREATE VIEW. + */ + if (open_and_process_temporary_table_list(thd, all_tables)) + goto error; + + /* The fact that check_some_access() returned FALSE does not mean that access is granted. We need to check if first_table->grant.privilege contains any table-specific privilege. @@ -3124,6 +3196,22 @@ end_with_restore_list: thd->mdl_context.release_transactional_locks(); if (res) goto error; + + /* + Here we have to pre-open temporary tables for LOCK TABLES. + + CF_PREOPEN_TMP_TABLES is not set for this SQL statement simply + because LOCK TABLES calls close_thread_tables() firstly (it's called + from release_transactional_locks() above). + + close_thread_tables() closes all open tables, so even if + CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened in a + usual way, they would be closed by close_thread_tables(). + */ + + if (open_and_process_temporary_table_list(thd, all_tables)) + goto error; + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; @@ -3550,6 +3638,7 @@ end_with_restore_list: if (check_global_access(thd,RELOAD_ACL)) goto error; + if (first_table && lex->type & REFRESH_READ_LOCK) { /* Check table-level privileges. */ @@ -4513,6 +4602,9 @@ bool check_single_table_access(THD *thd, 0, no_errors)) goto deny; + if (is_temporary_table(all_tables)) + all_tables->table->grant= all_tables->grant; + /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && @@ -4934,10 +5026,10 @@ check_table_access(THD *thd, ulong requi DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0, tables->view != 0)); - if (tables->is_anonymous_derived_table() || - (tables->table && tables->table->s && - (int)tables->table->s->tmp_table)) + + if (tables->is_anonymous_derived_table()) continue; + thd->security_ctx= sctx; if (check_access(thd, want_access, tables->get_db_name(), @@ -4945,6 +5037,9 @@ check_table_access(THD *thd, ulong requi &tables->grant.m_internal, 0, no_errors)) goto deny; + + if (is_temporary_table(tables)) + tables->table->grant= tables->grant; } thd->security_ctx= backup_ctx; return check_grant(thd,requirements,org_tables, === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2010-09-29 11:48:57 +0000 +++ b/sql/sql_prepare.cc 2010-10-27 16:36:56 +0000 @@ -105,6 +105,7 @@ When one supplies long data for a placeh #include "sp_head.h" #include "sp.h" #include "sp_cache.h" +#include "sql_handler.h" // mysql_ha_rm_tables #include "probes_mysql.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ @@ -1714,6 +1715,15 @@ static bool mysql_test_create_table(Prep TABLE_LIST *create_table= lex->query_tables; TABLE_LIST *tables= lex->create_last_non_select_table->next_global; + if (lex->create_info.merge_list.elements) + { + if (open_and_process_temporary_table_list( + thd, lex->create_info.merge_list.first)) + { + DBUG_RETURN(TRUE); + } + } + if (create_table_precheck(thd, tables, create_table)) DBUG_RETURN(TRUE); @@ -1777,6 +1787,12 @@ static bool mysql_test_create_view(Prepa if (create_view_precheck(thd, tables, view, lex->create_view_mode)) goto err; + for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) + { + if (is_temporary_table(tl)) + tl->table->grant= tl->grant; + } + if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL)) goto err; @@ -1963,6 +1979,20 @@ static bool check_prepared_statement(Pre if (tables) thd->warning_info->opt_clear_warning_info(thd->query_id); + if (sql_command_flags[sql_command] & CF_HA_CLOSE) + mysql_ha_rm_tables(thd, tables); + + /* + Open temporary tables that are known now. Temporary tables added by + prelocking will be opened afterwards (after the switch below). + */ + + if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES) + { + if (open_and_process_temporary_table_list(thd, tables)) + goto error; + } + switch (sql_command) { case SQLCOM_REPLACE: case SQLCOM_INSERT: @@ -2093,6 +2123,88 @@ 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_rename.cc' --- a/sql/sql_rename.cc 2010-09-16 09:11:13 +0000 +++ b/sql/sql_rename.cc 2010-10-27 16:36:56 +0000 @@ -143,8 +143,7 @@ bool mysql_rename_tables(THD *thd, TABLE } } - if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) + if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout, 0)) goto err; for (ren_table= table_list; ren_table; ren_table= ren_table->next_local) === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2010-10-27 07:32:26 +0000 +++ b/sql/sql_show.cc 2010-10-27 16:36:56 +0000 @@ -3017,11 +3017,18 @@ fill_schema_show_cols_or_idxs(THD *thd, SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' */ lex->sql_command= SQLCOM_SHOW_FIELDS; - 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))); + + res= open_and_process_temporary_table_list(thd, show_table_list); + + if (!res) + { + 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= save_sql_command; DEBUG_SYNC(thd, "after_open_table_ignore_flush"); @@ -3626,6 +3633,8 @@ int get_all_tables(THD *thd, TABLE_LIST show_table_list->i_s_requested_object= schema_table->i_s_requested_object; DEBUG_SYNC(thd, "before_open_in_get_all_tables"); + if (open_and_process_temporary_table_list(thd, show_table_list)) + goto err; res= open_normal_and_derived_tables(thd, show_table_list, (MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2010-10-19 10:29:21 +0000 +++ b/sql/sql_table.cc 2010-10-27 16:36:56 +0000 @@ -1993,8 +1993,8 @@ int mysql_rm_table_part2(THD *thd, TABLE { if (!thd->locked_tables_mode) { - if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) + if (lock_table_names(thd, tables, NULL, + thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(1); for (table= tables; table; table= table->next_local) { @@ -5672,8 +5672,6 @@ bool mysql_alter_table(THD *thd,char *ne build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0); build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0); - mysql_ha_rm_tables(thd, table_list); - /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) /* Conditionally writes to binlog. */ @@ -6292,14 +6290,12 @@ bool mysql_alter_table(THD *thd,char *ne { if (table->s->tmp_table) { - Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH | - MYSQL_LOCK_IGNORE_TIMEOUT)); TABLE_LIST tbl; bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; tbl.table_name= tbl.alias= tmp_name; /* Table is in thd->temporary_tables */ - (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx); + (void) open_temporary_table(thd, &tbl); new_table= tbl.table; } else @@ -7021,13 +7017,6 @@ bool mysql_recreate_table(THD *thd, TABL DBUG_ENTER("mysql_recreate_table"); DBUG_ASSERT(!table_list->next_global); - /* - table_list->table has been closed and freed. Do not reference - uninitialized data. open_tables() could fail. - */ - table_list->table= NULL; - /* Same applies to MDL ticket. */ - table_list->mdl_request.ticket= NULL; /* Set lock type which is appropriate for ALTER TABLE. */ table_list->lock_type= TL_READ_NO_INSERT; /* Same applies to MDL request. */ @@ -7065,13 +7054,16 @@ bool mysql_checksum_table(THD *thd, TABL /* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local) { + TABLE *t= table->table; char table_name[NAME_LEN*2+2]; - TABLE *t; strxmov(table_name, table->db ,".", table->table_name, NullS); - t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0); - thd->clear_error(); // these errors shouldn't get client + if (!table->table) + { + t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0); + thd->clear_error(); // these errors shouldn't get client + } protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -7169,11 +7161,9 @@ bool mysql_checksum_table(THD *thd, TABL if (! thd->in_sub_stmt) trans_rollback_stmt(thd); close_thread_tables(thd); - /* - Don't release metadata locks, this will be done at - statement end. - */ - table->table=0; // For query cache + + if (open_and_process_temporary_table_list(thd, tables)) + goto err; } if (protocol->write()) goto err; === modified file 'sql/sql_truncate.cc' --- a/sql/sql_truncate.cc 2010-10-06 14:34:28 +0000 +++ b/sql/sql_truncate.cc 2010-10-27 16:36:56 +0000 @@ -20,7 +20,7 @@ #include "sql_table.h" // write_bin_log #include "sql_handler.h" // mysql_ha_rm_tables #include "datadict.h" // dd_recreate_table() -#include "lock.h" // MYSQL_OPEN_TEMPORARY_ONLY +#include "lock.h" // MYSQL_OPEN_* flags #include "sql_acl.h" // DROP_ACL #include "sql_parse.h" // check_one_table_access() #include "sql_truncate.h" @@ -194,9 +194,7 @@ int Truncate_statement::handler_truncate */ /* If it is a temporary table, no need to take locks. */ - if (is_tmp_table) - flags= MYSQL_OPEN_TEMPORARY_ONLY; - else + if (!is_tmp_table) { /* We don't need to load triggers. */ DBUG_ASSERT(table_ref->trg_event_map == 0); @@ -211,7 +209,7 @@ int Truncate_statement::handler_truncate the MDL lock taken above and otherwise there is no way to wait for FLUSH TABLES in deadlock-free fashion. */ - flags= MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_SKIP_TEMPORARY; + flags= MYSQL_OPEN_IGNORE_FLUSH; /* Even though we have an MDL lock on the table here, we don't pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables @@ -340,8 +338,7 @@ bool Truncate_statement::lock_table(THD /* Acquire an exclusive lock. */ DBUG_ASSERT(table_ref->next_global == NULL); if (lock_table_names(thd, table_ref, NULL, - thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) + thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(TRUE); if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name, @@ -393,26 +390,27 @@ bool Truncate_statement::lock_table(THD bool Truncate_statement::truncate_table(THD *thd, TABLE_LIST *table_ref) { int error; - TABLE *table; bool binlog_stmt; DBUG_ENTER("Truncate_statement::truncate_table"); + DBUG_ASSERT((!table_ref->table) || + (table_ref->table && table_ref->table->s)); + /* Initialize, or reinitialize in case of reexecution (SP). */ m_ticket_downgrade= NULL; - /* Remove table from the HANDLER's hash. */ - mysql_ha_rm_tables(thd, table_ref); - /* If it is a temporary table, no need to take locks. */ - if ((table= find_temporary_table(thd, table_ref))) + if (is_temporary_table(table_ref)) { + TABLE *tmp_table= table_ref->table; + /* In RBR, the statement is not binlogged if the table is temporary. */ binlog_stmt= !thd->is_current_stmt_binlog_format_row(); /* Note that a temporary table cannot be partitioned. */ - if (ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE)) + if (ha_check_storage_engine_flag(tmp_table->s->db_type(), HTON_CAN_RECREATE)) { - if ((error= recreate_temporary_table(thd, table))) + if ((error= recreate_temporary_table(thd, tmp_table))) binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate. */ DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table); === modified file 'sql/sql_view.cc' --- a/sql/sql_view.cc 2010-08-18 11:55:37 +0000 +++ b/sql/sql_view.cc 2010-10-27 16:36:56 +0000 @@ -442,6 +442,12 @@ bool mysql_create_view(THD *thd, TABLE_L goto err; } + 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)) @@ -1648,8 +1654,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIS DBUG_RETURN(TRUE); } - if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) + if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(TRUE); for (view= views; view; view= view->next_local) --===============5989403677333247201== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/alexander.nozdrin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alexander.nozdrin@stripped\ # 89av3im1e5z8c990 # target_branch: file:///home/alik/MySQL/bzr/00/bug27480/mysql-5.5-\ # bugteam-open_tmp_table/ # testament_sha1: aafa7aec9aaa4c89119ddf91cae96c5a1c002cab # timestamp: 2010-10-27 20:37:03 +0400 # base_revision_id: georgi.kodinov@stripped\ # 2vo6z5jcpdnzes7m # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWSyyfPsAJEh/gH/9FpR///// /+//+r////5gPf7xvbava+dHnc+5ffY7vAEDe58L1m1azr7e8pe97fMKb2++e8s+fO++99993e0C vd7gcQGfZou7huZRQTs0m7jT68r3vB8HvdQuXa2VXTIBlkq+JdFzy80xeuJ1tXmiXN3z4Pr75db3 u75rp9dbeczVW7tM2dzudmrswd26rG21tq27OOeunqvK41bT7DXe53Tz7deUsLS3zmjT613hKEIa ABDIE0Bom1MpmRTGU9RlP1T1APTSaeoeUHqPKD1NHqCUAgQQU0yTaJkTymo0MT0mh6jQaBo9QAAA AABppoQU0TCMpsUp+U09U9TTQ0NNDQaGgaAAA0AAACTSSEQBBPSnlTemU9U/SmNNlMjU0Y1AA02o DQPUAAABEpATIGhBoE0wSYnoU9NMU02lNP0Uek9qjI0DDSbQQPKaCRIICaaJiGjTQRpplTNNGTIR lPUNpNqaM1PSeoNGgZAM3CHYRBc5BRQ8+ik/1U+4T+QhQTx+WeWFa1rUv+m3993Cota3fffpJ/91 IKTRWl+zlhjPdlM+VvF2981bLPl6Lp3dn79Cmzu6dMF+dmcufLX39Zk4iZSstJXoMszWpmnZDFUK 61GPivfOyBGC0+wutycqlsPbc+WRrZvm9tWdVcDeC4+6UTxe3uuLnhzL/s0t7c/Np9l60lnchwei H/XeE03KXE3EzBSyt529xW78rkIm7x03/X8f8vx/Bfx/j+b9HXt7eEn5zOjwP+OnAnvjVsAzLF51 Nr0FYXJLsQD16S5LVTsvV3uJgl3I1nHTDZCxI1xC7NdKq9rHDKqyDh71fL+z7oTvNmt/P/7aT0rb zX8vTKUCk5+dOZ2NwLDy3D1yOPV4W7n60gEtqGj51LZAoxNHqBffD4LT5sNCdufHL35O0Jj2ROzs yrDqW/snq/bS/8Y0T5RfhPIy0S1ORtj7XjF8P0GIo9oyP+vE1v+uZjVY6Nk+rlz4WvfoL648Nbiu nTPs846Kfb3x6YY3Y85YTX17fXrGMc0WaipPgzbzKO1mvo8MKy6+63muUNOCDSzUNKQzSdVyDghc rXg1Y25+DwkQ90nYueafPVkrIhjBbxhdPZcItkanXpIlI7i1MWPiO3MLvcbdrAOCAMGH7JFnfPOc T4IXbJNgZ+PyEm2n7LdRoXy4it2VQWVtQSge58G3JENI9jVCbURSLeWOZxfvpEE61s11uMpwviay kWPVMURCC/2h/sMTGhe4NIm8GnNpIYxSRXk1kJ5UgckPGkPhZ4mSaQ4QrIHaw797DSoBxlnDpEEj spPelhliLsphjsNmdafJbEJE4ebZsQVh0r2s4eJDkwMLFrNUwNVptE2jEtkxnKs6xicHAcWM2goS hBeyu7VF8WJwEcGMWl8ZGSs4UnkE/91BrgTk4UtTYqiMiogt6p7iMIAIc6ELGBILA+80EIFpQPXY WSCieugeDjJCcAfLlgYQDjooFdcooWkJOeSIp8sZFAsiAaH24+gmiaH/xMNBTiCODxSU/7QW/26Z rSuS9XyT+AYKU/6wke3x0mgf3xn7Pkxu4RsCYKYOz9/SCJghiGCM2Ccx2fdk44ZZ6qj9M3+SiZX6 6kkugJSJbAN8Q0/Oa02dCFJJCHBWFhc/tGpSmz7v35gNX4hCy2tA7iHZvBPvBOQEjIkgyBIEkJBE goosUWRYKSCySCwWLWib1RD3/P9CIgnKVl9aubcqseXl6yEm5ZciknPV6/KmmbGh0vrQRE1ZQXvk Z9+Jy9PBxE3N3jEDEShqvap1Vqs5pzWVMvci4WU5aDn4opmEoTujTS4wna0vFtEiItoraPfAtGHB qmJsdVEXTOXIyXikHIrDvZ2ukgSHTiTgM1ZEPnJpiXs9xBfOXDkQXNrugc1ZUZIe4dGTBFBpjFSK LC0O2TORe3zGAy9USXJLTT2UpliVh3GcRqUZILuBIEJYrFoGTTrDxfDK17Wi1nejbLh4skInGL4s MykBkh84KwSSRRkigaMkSDYHMAuz3LoCLRWayRcgRFIVKrMtt9jn8Ef1G6UENBJ9DtoFZ4nbvGJn hznQ8/WR/XMTuc5HEDiVsTf9W+LdNXSTohz+c5yNNIh6tD6yVOxEquEDTPWa7IoHyW1Ga5VHZNST lSEBkm+hPL496h/EZRhTb8BRESlNSCn7ZthsL1DzPEzLz/SOXRGSp7pTNU/UqCvQISFlUNesQLHW kRt7IMrpjWKjUR1nvdQIEDTzWHeZEt4Xpay4yhC2wU94p/yKOL7+M+8WTppzz+eFCMItTvoVrlad g44mxoQvI2kxnV3k9vZ9HXnb3G732mIlqsr0sbfj4Kkm9quZ2OBhd1oJHER7hHAMJ42G99W3cOaf hKLOXPA+vMq97QARNR4YE3xbilhnM+x6AhnTReJ78JwOWyReoXcdMs+DXt9/vAUNdaJ3Z71y/FrW exYowOOv24GUrd5VWdwufoHHt5Zi2M331uqUr7ILLsK4sDIPLRt6cVDCTz4WydpttBtxZHUoKVB+ NI1mlj4QkEMmVPT+FjasvXWy7wSe1jPXyoydM8l078UPlaNqMpOPK70WbK9DpPZpF3BAjN4FU8nn AaWYht2qdvqSumblHn8IcioxllQQiqzc+L4SSmMeOzDYR0k2gzpe+C7c83X/D0ySl93S94cESkqm VA8dI5S89ThENiViyV2sbc+QlOfJtlq8qNrkz1XuAl1BRua49nRjOi/VAd3gV99nicDpSQ79j1qK Kpa2962BU1hhIfdzXbvu7bNonfMiywdsWNA1ap+2I0aNitbHPI5H1SWVNuSvOuIm8O2erY56iAjK PYeBfcI88H1nfQ36alSoT0v2DeKx1QmpWumGK6Wg5qnXKZJXGzXyr1X1z9hq6JX9gILKl73BDgPr i/ItAvz3TfuObaGk4HIzzLyu4KAaLuIltl9HvUttuWvA2D8TMYCj57O7W7+rVy1dXpcXxNHWjtwu u/MjoR4a6Wq9x2kEQQnnvG+fDQWuOmU20i5ZFvNKsizX7XzYtAXGVptbhQQjNNJlta9NBK/RANKi lVrrqM5EfFSpZZ36bqm2a4HPC7GiD9Djpqe7JxLqQRlmVU99srJrBtp5xvMYU3KsGKtoQuWlDGE3 OAFKsdOODqssp3hLO0r7MXwITuV8+9i66Sq4Iodh5gQ9glQJ1yRaCQsEhQSFBLsEGLpIayw266qm iIHOOLWucF7aN3NtjRz31qOltraSxaijC7+bZnCXU+VUPYo6h2VmMuDqa3fKQTaX15eiE63D0cPh 3sh3ku7XPdDtN9trQB5wbmb9lRRJrwADDzzndvccYgYhtuyVXG3Hhy2vAWN+vVup2Oyp4Rv3W0lH OJ5i3W+ls7RFlztLQ1jL6lfc1zV72iSsRiMmrM8LxQ8Qm3AsPluw2IcCfdDR1EDOmwONmiZl29yI TuW2k66VU9yYNRaLLegh6nDaYNn9ZT7TqD0tPs1MRtb6llcxYbbWOt/sQbb+XnVbl1FOagg+um1m OEHQbRJofqa45oXo0kRcSDsqFZ1fhkg8/vh6TWZ9ctR/MRISD/lGkNPK7jP750fl+mv2V++yr30q m3l2fm+3m+fjl3vp69dPs7b8M/y0x3cukUfypNooN2NQoKwwZIITYVXtofA+n6o9OynW8nls4uVm Gw7MFc/NT8XukA7vWevLaSH1f23SmpSiUtLPq1TToCFQUhUv5VVVVVVVF9UYUnMfuBgMBiVjLogt Zs7mDygRk1C+mnml6bKyoKwNyNqUgFA/waD6cYUH1NfUv7pqycHljiLePQEmocMLByNBSXfd/wXg IPuYkV0OMkjwP2yvTX3wGRVBp2NHkWVH91CPTNweg/0g/Z/hvkWMXlYHYyQzne1JrRTgSnsbwy8f WpxC0pUbhfRKQyQRviTq/xwlDLTH0eiek/v18naXvF8zSPon1uQN6PoJOVh55jkBxZqGptfB+eEX zw+u4vgnI5vJYZKN9alP12nzKB8q5rZiyOoVrMWChfMGuHc0HR56duimsQzo92j+KYiMNvKNgukM /16J/CfabrajNO3PPxEcBDEMQxDEYrC6/Gf9VPo0z4+uDvnFdW7wL8iJVGCTt7I5dXF4r0N2kb88 MvcRDjEPdyO3Az7L99ubNv6ik2zZlWXJk6EgplrssD4dMFIMe4in340X4wrTykSFA+Iq/ZO+SCWH GeIKkXrtr1beps8M8h0kqj2YZYGbGZsPhTCiQnQoCIIiMlIMezX824k489V3oTHJh5vlvvP0CQjc TduE+eAzGjjM4af4IO8NXH0WhJ2Zh2+71d0+1avjVHoEPiITEkFanJihUIVZO0n5TWVQjgUuD4va 9tdl0CW3PRz/2AHQQoUj9lFlGih4VTxnecpAOEhgJAIVFDnCEVX0uw+wiv1lDNAUob+PdAoW4+S5 DrMmYS74CZCwUlcwUWaTE07xgZmFD1OuCw4wtt1msljoSaKUYrdZyhJ7PnOz83gbznBfaMRqMl2m kNeLJ2FCXIasDOFMuDGwoKvLUsDcxYMoYxhiZbtHVpMhJgJGUgp5OY60UxKj2w4Wuuu6sYSebqpL lgzeihtqwWLrVHBGGkXClWmV1/IfrZFrq+06t1si8nOgkTNKCCIXIzmpTEIyys2bifr4K5X8S7Vo +on49l+X3e/5vDOyHd1deZaFEomCaNFPJvKQQZRhIceO82wrMphK2F6FnON4bexuS6gXopVJVxxJ GBchEibBkB7xCPlA9m0R8oHkpeUyHDOX8sIPIIisv+ap8VBD1/ZsP2O/hryxBDgiIbPRyGOXgQ+6 a3N7m7v2gQsyw18tPaw+JDZgBphJwq2wEzQS+DXG2KYQWq6y7AE8d9LgPcREHDI0AhkwSwohc+n7 jSCQEiDsCjMUEYfOb0O0YbfEeB1aj37O5ohzBFRSAEAjIAChggYB+Z6PAq9QMjmRZ3bOi0wIXDTD qiCJyfloGYgQnLAjvY2IN/pL7LVqBhoeyMkyMYlaDY4vcrgwhAu0gwp+YZJVzm5G0KNZ0go3FoyY NrmrvgvIZwMxQwvgcSrsQmBR6cEe4gSoUUhuDmxYuQSbnA5RBkY3HHHyKM84Pv/w7lj7n/nbv39X q8PtyFh199IEervyYPlfEwdXfxZrWysKjlizPXeR52Jf0tNLF3VsZm2g0KgCS/L/eD8lkB8zGnKQ XiMBGoRfX8pFRFl60Y7xZWBhXnqV7NIJR0iURA3yovlKxIaTvGjXBUxsEGBNAoOeE4ripvn8zcmR eaTylDF5WIOxrbLDIm7kyerCXdd+OhH1Lstu3fxWp6CG7FG7FGQOpPXJYsMePS9XX0eHfr1fv534 +XVTxEbT2LnTuIbtRo9OIkUcYVu7OO45segZMndzqdPpzvGqdnVtOuS4woiGzolxb38nGVT0CpRX r9UJHO3fEOjbldTPZTxuBLpg7tJJ4lddzOWjLnYkEQiVb0jWU8TLLPQ7Xmyp1piFsSNHN58PvucV 3Bi6X8WLXdWy+WEozKmosh7wWMaCZgw/VaZUTnt6g2sTYRKoI6DjBmaTlOfhoNBvKjN4ItNUj2gk SN2Z1bdhuLxAXhIu2ortseWHLEkm0+ZKCsm5Nx1lm9XazrZsPd5WGpuHXYEze2m5CRriCiHkIRAg 9y5dO/BorSIiIR4lvcTuPz0WB2M7T12FJKuLfuNeihJhPBRlyuPlIOh6AkyLAClrDYWlM2qOm7DM V5cGhtEIy5XcF5q+VDY9ueS5HQUoOxwkp1nq5SLuUMmBhaHBhYXO8XXBKWFEJNzkmMatkYhQRBUP 6k2Orp02GVV2yY4bYCqFR9xh1x0LuTgfhuJL5ZCNnaSwVA3sTTIiGnUtiBaRKyYsNpaMQS7bbOVF BtN6TmRvLxiJwPefvO0wHpKpgYGgawRP0NRlE50troOw6iOx2YcXLgnIPOH55d+nfNq3hBJ+QzZC yxV12EH26prtejGQPmEGEGPkJsRyi64scPLKnnaxQJsFRfpMlGSjCw6QtkW/qPcY27mjuLSLEVTm KKfdQb5i2gslrHsETeWlo8tmC22boHJRY0OnbBcyXMmLKy9ioFVh2U9cnCkVu3k/Uc4HoEQfueDT yMQdjzMEJxjdRbjmuSkTb0ESNfmD39qGuyGvBXOgrr8JO44ypkJPWIaIkpSaRwiXk4x7hrxaDIxC JCYkeGoyHcx2kRK4vP4AkaDrOk7SBKFs7bzUZrE2HEzxeVeHJdTvHmIDtxBcU9RftMWL4hKFCRii /fFUjDZ1RewSKNgGwTKacWyhYHMjuWYgRDJitKXosNlz1i6nGYRUR9aggUodhD2FNNMJyP7bucBg 2it4lYV54HKwJwXKKiQfq+zMcroXR4DJsYBjkFZU9qpBryFuRU5ZidnOStjr8INxTG42y5MslLqG aJQuGk2EybGtVbWxXoRyBA8nlIl11BId/fkOClMqLzSVGBaSkpMOScRPElNpHpKys1CnjkbTMsyY sM3U3KQc92JK6SUhI9XyStCnqhyz2Kijwivse9snoFNbEKx6jY7FjM0af2EjJGPUPYfCONBRhPPz 6W65fnJgo7Dj+kaylBSMdBXGl7hSicU7hE5zrH49E7OJisxsRKB18yngdyI5Ohox7ybpsaLIIhtc oDJmYGLlDBc9g912L0nCmBZ3QUqySKmBiH8fHCHRBNFOUauekjpo2OdH4yeCZNG4phLHX5u+hSxs bwfZNgvQnXam0yN5xLSwuTSb+nccC6skBENW1VNOZtLR4x5Vbz5YhpmWZrjfJnFRTEWhYZ5kooEQ wq3jHytogbJmlgLKvs2NSsFNRckw8r8uYrG1A9mF8DMlk0YIxFnbfnnASbYHMgiEMRsZOpci7lks fD6Onv4noZL8N7hwRCYOp0NxsXtVi3YqDoWgsZMEH0JkzTAviKop2NNK3gNxiMJJyJKaBiUgVjzd qiKghzk5kE5WYkSgvLSjcpq1XkwqRmJjSbyTQbhjGSQ4DGzQbukyICI47g0MOI7Vs5hCNhkGd9N3 +ZwucQ9EcTbOLub2eRaJtVO7UTYmyxm2MQ3ZzAuEuSZxn2bQCKiYFKwuo9Z5m+SSqBELsrOzdTsc FTQtfIpHW5cvER8brEoKHl4TjGyqQyTGJa+gxmpuRrhw4wNo5wKeYpKnZQ0KIaXaOzlegsQcDJcu tEEwKX9JBoe3ogoFMj4WaqzdUO9xEI2MGS5G4WQYqSkuHPqIDhRR5fjMU2k5rNJxNI4lOB2puNhI KdZQcxw1aNuTZsbWHvFc6x8JM3Ys2iDoa3vjGMWrBnGLA4czNyPPfLK7WzeABEDmrBWD1BbCk0Xd BoPoMC3pvOA2SvDMtctFnDMvyGytu4hzkjRWzTrZzB0L1x2vptsZGVepuPNYkyKZeWLrRDJ3BEI4 17XMFixudD4giHBuXIPWeRBc3NFj6Pnvc7HTIrGhu67pAMq8x3a3VhmYgkbakqbvsSu+VSNXU3KA cEAIZLAMOweihzOCCc3u7bmNcGxgvchyTYxve7nD37HA1KLZvSQYsu2qvB0OfVycZ3lcY3HnFcHJ bgzm/VUkXOgnYa1puwnappryUthOs6zY5Cdhz73OK1F2y0iut33h2JoEQlRUJ9JBRR19WxIIhEkM AeXhOYVg8KqKM5R4p1cxsPh5a0K0sHaM1LUCR8IPuYRO8IH0/SOVDVlIGK4Ltng4yl3A4mSKRLjG 5CPRCCEQVAiDM0tSCEoiFqDDNfRvapbfNjU8+lHfQ7m+C6Ycp5BXa+pk1/qZAqUCSNpoYbaHFyIh pr9bNfDLSX4VcYylOBWDJ0gIdYw4MqkDecuohWxPOd1n0u/xCwHvkbOBBBBYEgGILONdXUbrzQ8f V3IeND8hsgoogmEMMhDBRTyYoqjh6Dgp2CbD3nV3z+w+wGD+xCD2/UTxMESB6Oev423kZ0MX8cDT 8G+55t7xsOk4Xw4OG1324NVtzORq6DuzCVgoILEVUPwBDehgWEBBQFWfAjqB2+X6wTeZvIj9ERQL nR+QzhCGm6piKWD6iQlh5zT2mcQE64dZ/2BQf8F2iHvSfDOVhXXIf5n2oXX21itz1EKj8BXkA8lZ YEs/T3ipmYYhGLpAbQ+ZC5dKDcZUJGodWoxzYjIoen0f8cLrZFkEiMiTBDP/4iCKiAVfZcmxSU/c x7IhqJy2Af0LGZf3fl+VX2yOlMBUjO7T98VrdE5yrGFZ3Ds0JTLg8WZk2kxdfIJpDhSYAO5fXAB9 Wc0XkIkKU42Ih/2htaCa/W+kXOYgKkisS7S6w5DZAa3JsNDUJ1mrpzXBXcOYB6eplJIIam++/fJh 3Bk25PWqJsbgTv+vGUPzX1+KFn/pgiIDAP/H4dcExhiLIG7AWBtEzRsCzlFVRUUGlAomkrda4LTD Y2RkL37BBdlyRE0l+BSJcrMx2pKCLwFSEOkMQZSnk1gWRQIilYlaQEI/fwBbuEyxBS0w6WhRDM5C sFDEUt5XSDaYhQNzuwzBED74NjwTKJAa4MQrMci14c7NPmMiSJJH4DAp/s34sNsFEBc5U/RR6Git BEGvDU8lzYMauNC2IPBVG8TeCFEoOIBkU3AaFCuIkAePcItWJvhq5JGvNkog5E5igCYwUElCmLrB JTUJuSGAKhUM2E95cB5CB9GhAHEhan23jguuUM5sI7YddTSqNO0Q4UCQ5Np35ZzchaHVlq/pUFZW sCK85WgGK4IieBVHLoLhJFEkFBoETzokB1JI0kjeeFLc6BWTdCzWAXiuYiEIK7TFzAVAZadc10ES 3BMYbcscMRq/Z16cxpnz+6CWhZgO682ALSi28vgoZiQ/n/H8O2tpMMUAp3gmGevYSjqI1hDKOUgX xgco6AEkg4aLqQwDrOyfBw9iFZohb0mfAFMJjBYxAM5eqXVwroBQKV81YdSEVdNzoIcCAcPKobRC vlNQQQGgT1AcJXRKTdBUqkEwbQ8SBglBxDjMqhdgC1XqaI0AEi0R2vDzqaB5wadMKqaxI+achOId qNNRdD+e8tVXxUuOcBtRePMUW4HRYiyv1TnRS9C0SWQhGBAEnLUA5E5xuEMA4BWVM38C0KAvLacw VlYQqgJL3OGrEtHnTn2inOGhCoS8HIQioahgSZhTiKgGuszpAkU0HBRALb7iqEFvnwQgJm14Wh0N GkoIxSYp4d399zWGhV4xi1Zg4NrUlrLY0fEKSCcqly6VXYIQtmiUh1NuGYOqeCZ+YisTFV1UKpMy CoeIuMDBCgCwFOrckYHHXlQhMYoqMFQRAjfBaaS2UIv4f8/YVHvOUc2G5Uy3FIU3ll4sQtyTWwL3 kmZqGtIrTsp1gPa1DNorioviehCWKAPRHqJ6WtCCw9bkFSmkTzEiJY6UNsb1B1VyJzA86mB6+akh IQkIEh7efSfScmAJwivyCBoVNhrLywlp8WfaJlHEUuZtNNonPEAtucxsJSQNERXX2RFhRIbSNONy SYt7nmsmkRICWIdRzEkhCSM/V9v1gB74nvT6s2jqpJvpTEZ6pdEjNrS9Q/HX6uelHa0trdpcvQJy FJEwlBRjkTFAHOuKQ4rZ0M7JbXt0MWRRwC7A/2VXkyLPHlSIhZUQrLWiyummHCwQFdFTZUTDyhaN 9q3BEXSG9BYwXpKBC7RplSw02MKCWISqWkpO0DRCErTrqgvkWl9hNfSbQX5f53vBL7uiSPtaU7Dg L+gLaK4pAhFYuu6qE7qs/OyIeUEBShRU1hBLon96YtdhmYxQIYBDBLkQwE5AmevUPpnOWSHM7KEO TFIPENsyxDmDIoS4MoMLaDh6S8oMmDZMogkpFIKmS93Efe2aR5BrggycMCFgY1eH206TthgJtph0 AsphRLOplFRM1FxikA/uSxSUcdfLkbWVcrd+tnMtctFzkbnJ6eARYihCUKUK4ofATUVJqW0TCSaE uvC2xvE/ZpsAhGlEpAvsP23a6mxPzlv6/GetYhqSCclQRn/bOSDz7zLyk12UmYiH3H+J9w4EPZ8f uHkD7xxSPPqHlQVjjcjiWBwLDcUF5+BQcxsMzSXyGKPWZsTYcR+7YGs71OSllBUkf3RRUIMXqOK4 F5B+N91Elz5HYISoq9cdQPJLrDkIO9MC00iqK4E5KZF0901cT5sTacTqOw5TEO1wbUQsLQE2PBEF 3BgcEcahOxDiaJICl7dAmzepxgJ+22yIUhUGOdJSY2fab0IYI3/Z+/HFbkXc0I+qQG8lFM5LN2J3 fugzFzhXeH0jCYIJm2uIMJITvp74foDh7cxeDmzKbyL9MCiWxEIi/wFTxKlOLIvrzUQvS/AsqD+J TtnYZupOol0iSDJFB51mAfy1JU5g0tG62iGkUGyu6EQ2ofDtDcmJqkAaHIkKWS3buy7z0BWZNJIU BviIcm5o2IY6OjA6irDdEkBMve6wWioXnKygIvwAgx8lNBzdwJFV1BlHqGeY9hCwySQU93oOJcHf dUnpPEvcaiQ8yQh0nqIR0BAqLOtIVEpsJikibSY+Q4nkXFpuKzzGnKBEgUk51dVw7SewiTkCgY0l RxCsYqOY0jDykiHbswPMEMgCQDxKlS7pKCAtO2D4XxYg7zuRsLyDwN/p/AxDrLupCSAkMEhdwzYe 0s8S4kdx9uR8BmZ7ODMaIfNwt2kNPcVDqTsMiq6SAaVRXwsEDkUBfAuqEkaDidZ4QUW/Z3EjqO8q TO06TiUHTLtO86BjtJignIxKReJgdwIhKGyk6tgongPDYRK1DlgFRyNNIyOWBrNpsLz0KBrMh+hO 5F5F52nL1F5KKUqMKgWmsqyKZMKTTElGiLXfDuPRymh1kTGUwlOP4TlDUr6QqeauUe0T4le0I873 pOpConRSg2w1lBGElI1g9xZV10RISfg8/P7iCyHQHu4x5kfSCAdowgh2wRPPGcmNcD/DwQ23G0gF 4KYC3jB4j0caVYmkM+8fnnG3HtHs56gnSyVH5ilgWEZBp04FwSyMZBF8+ZgirCpUjHTAKIccerWu JytspaEowgpIccQQhCAD1VFPA7ieJ47zndMSnpO0nHlx4HipA8TG24RBS4O8wLxENhcOlnGKzAvK EuQlZkZiBGQhsRUJHKWFliETkeY0dp4FFzHwJd3BZmBBuUDUj2mJckGXUuwciBbi0iXnyDYa0aBo WsncVP3HRZ+g3C9bQkY537LynA5YKMghc4ja4SFpOaCscntAiIhXQUsmTOPIVKLDiOAqAv5C9dIq bDXXklwULjKYGbOJBMOyMyXyu3y9UeV22iFZ4I7p2D0xUUU99UlZATMHOKEgMkIjIK9kSktQnKl7 EQ9vMI9pPVy1WhxgU0MFogpNkoKVfrte0vahEJeTiDLspNnM2L7FXpmYpbKbkgyKqDKNvhpykq7v nnUvF98D42smNSs4W3LvfhbbiZyr007tQQCkrJEJbK0jmF3ZhRTlUVUOVjUoSQpERhjZnfexE52f WHnEktG5ushEpKnHu+PuhN+42juMidOrJld1ky1RZJpkWKHcyKdzTc53ou+0e3ludsoiCOH6wogz yS9T6PuwFaiYdWit7uRLCikiRMmIS9hQLZbk00xI4GkUtm3bj2FTItNQp2oxE4kDcUDzcU4Gw6F4 +n2r1ad/CvUsvgZVmiGiVLjSKWEC45AiEyeBrIGZ1GQ8qKCJ6SJuOC9grGdo+LShjPOCNwIYuOQa ncwCLDsNMcvCnLpoQ5gw2kghIhrMIVJ0OH2FFJGrM7TO2xmhMQ5QhhLMtJoXKULDwLiB9wF8r6Tz BLkSsAgdQLwxI2X2XwRwqywV8OpIQe87RFmliLAo0eJQnydT581cRaWmhq1EYJIchzxeFkotCYyZ VMkEUeBq8yzqEmQSj3lzdNG0qb+B2nN3u3MDMZqqZYvRvRYtF8IgxJUMxJw4edMgxKypQjIyYouw r5h3BNNljlo5MUYp0sIR6PlO415FZQIcL9N7WtkFhGUoIH5YMiSIr39nTuo8uNMkzULIwjQgBXGl KAgUC8ZyXSuIpDSRh8LRApjnHbpuH5XQEmwQ6192JobLCKFopbd4ju022vkCi0QOIiBjewNQ5pes qzS50hHVa6hSCIKLtLoSMiMHwCxVL1PrY35qWmOdXwMDRcGYmGQ/wyp1CR3FQ0E5vPR17CQ2hoHR HPs1oWplGyJIFhIQlZfuH2sJ5xEXVgHkUeGE9rDflSQ2R42NqQL8WpLkAthiYMijAg1UrhAV31D3 sR1OTwJQMbGiZYKbqkpmietRwokihpSJdKNoi/quHQpYIRBO016AHpI9HYeMOqfOyQBsEpbbGIVg i1u+OEod04lxTDxEB3kB+GleRKfiTGc/wnrPgDqI9RI9Y6ScAxHkRx0DEhMWHZ7bT1EhOKTmCxrL g7XvKrSwwLLJaBHlJMesuIIIcFCU6wwIETNBKw7jiF6zeWIc0+kE6n8YJvQe+e6ayHyk+MhzwLzv p5q0QpyPngvpPjVK0thIHuiDR2CxRBxqTkM5zo6vIoH5HXrPAV8xVLpjPSeR0LwyAUNCqS7VEhc5 EHWLl6z1nvMT1LWZGeGBaCDhyWnpOo5E5yLTYioJNBkYBFDUGrkZHedxhiaCnONN3hyec27dSbWW ozPeUwA4VEwGwilKKYNeIkDj9noOt3X0s4ZKeBjzprQo7gPaWgiHkdhftRcdglwJHmPA4KhwOsbb GjzPByAfemxzhgc5cTs+c9B1dxaE6UCxYATr5KdaO1owaD4J5ChWF+ylBi8+FLp5uvQvsiPze6mI FzycLCsJJ1pB4siqS2wUkURShO6eKh+yKB21JF5ZJGEQKg2MXWfEUQTsFFEFRtEHwnrPAWo1jxi3 wfM9mawTf4U7q6zQd5pPCVD7PxCEk4qJZEjR1YhTne8xPD4/iKHrS3QRGMES3EkWywuPA19CCyzy tFZ1/ia0b1AkiANASuuS0iXl5APLPYrPkb7y4LljErmTF9/3cNbZhsmtEoorFmOCBt2wh5ebDvLn Uez4DyeZ+jc5+YvOstbi+JwKrWbnHeDX2ApqQ0GNBaJJ5jOVgtzQaXtlCMhz/CRF1iEjeXn8ity/ R8sDSQ0WjNJt89/rGIkmK4346Dk5u3KbkMrQOeXZnF0CItMsxJEIaybucWkUmEr8LQbJUQ1r3Bh2 53JPs+YL+l7+zXexSKqxhBFhxT1+TymjqJ39h6IfW7CKoCqKsUSJ6mEKwhCPFQyIQJ6MQ5NKphzg h64h+YlAvOqCv38HKetF0MwNuwskhWktwfZbe56PUQXsOLXrN5CqWCqkKBuXO37vWraHlwPd5GBq LShuL1cd4ahj5hTALyJ7ib1mg6wOY8jvSB56DpLjWe4uMwq8tApFkIRdp7vGcrvsBbTQayvjjOIt C0gXC2UHsf9p5xidYEeV3HXXWqXAVbgrO1DguBeHAtMDTA2uiI2nOdZkp9nI2g6KihscED0VNQ1U ZIlZAinPE1HGrRQtkCKj5yyatDsOOombDJaxgjMuiFcGOlNDGmNTq55kKEJwMhZlIs3JQoGpKWYM /H2oDcbH9+99pIf3VeWvgLjgEJ8R0VdBusDkEZEYCQFygAlCLIiOkRYNASIjBDQC3uW7aVabq06N M5KLq45j+a5ILASFrpbvfxfTQorn8x+rghIywLzV1yPMVNgFKhetxioTAXsagGDY9vcXLmOYNpzn gWAVbTZ7YIBNokPqB0bexagRboRveQuxnvkbjeo6VT9fOS4qjRhosIKEhSKM35pgEbaMH3mtScjz GlQSc3uE4iSymvf96s1QZ9rZjrE5ykkTaT98l/QdqYl1anb+ga6CfDPL2GbraNZAC20PUERnKYct RdFymR0bypRawSM5BWaILbQ5joR8+BqNEkF85ATMS+qqgrXrWpDw9BIZBeGqv2WInbPtN5xNtisq bl+m2UqwLyOB1JKpzHSZAkeqVeyFYvGeLWHpkm/cTwDuglBhjxImyhGsSBPiJRvg+wLzJaShfNHu 9xQvPXQ7IjkDT/BSodJO07udt9Cd4wNNGool14sZ+9YVZj/AXIsxjbvLmfnYXUtrsagXhJNAb8a4 mtK02YpX0uhdFE1SVovfI2B8p1UiVIpLEW2FMqUg1kQPiYDhXaNrrjLFghwDPeV/IeJiWmhWEA2Y tsXLAaCiKUKkt0ZIW2IzMySCZJAMyFuBf6mClMisqFLA1EIN3x1WI6IBZDWh+uoqqfV1UPdAfwrZ bzhIcMARgnHVlh4Hh3Hwmu0bYSKrWg3EF6DohWmjSzN9LNL2M3tIUsi4avojBPMinkO/ML5DI1nI Lsz6KSSmhaqqC3ya+RDZdigu1swBCGJgrtccKFKxICnGUCm3L2w8/mLQ5S55TOGMxeF8xw+R7QjU PMx3pAqH0of0CQ6WCGqB/MnEnC8aSt5SBGoobzQda3iVhYYLA9qSPScwVOuYoFdVFRuHQewxGTgG 5MQwHqi9cE3m0+Qqqv6T7ZrUC0ToNANhcDIgBOrgUATmJV2LEZ0VhEmtiZN0TW8BiRVhWr5I7XLX 74hWEILFiZMWGUGRtQW6jjbwNOIdjFqaITCBr3MNKVKJFWKJ8zPhYfHtfSw3OWwGfv8s0aiqsVGR Q6U3sOZ/KHRf4e31H1+BBRIc6BR8GUZMZCwPWhPNgoc/nISYA/jFBu5LUzWB2xOEOb5RsbUzuAWE uYcnRCRgPRHHm7jFR63pyKoX+J7hdQ2GWhZAm0onYlUftzrbuif83NCRSrT57MfBhhxP43cQU6lj hNJttRT2iZd/PfKsKlp4hRoP9ge4uK3Q2A7vpOTlF1BECGeDBDEiOteA5wyEMt4nDWl0VokPjON7 BEyXI4iQj1xpBkCRBDPFaRE8Z1i5GhLaaG8IdhPMcRQUGyykNxluFJ0UzOgYomESkE5cu/v3YSJJ 6GQ3pbe6Rk0l77SMYxRgZtp86d/UcL67rcJF2+E85dcWlttZTo57BE7HmZ3I43k5OdJpsN57SR5y TiUHvOIgSioKmk1lRscBdAcPOdMToE4SZbzgDirhCICKKyPsQowRLaijaSpKWkFI+91l9U9GtaRg E2T6Ee/5DPtDDfeIxiuEqQqKFAgQIcZBF3JAGxOv0WWIWEgSzcPceY0cp27VZmZcn6hkLFlyjpLq bCQPnQuaJOi3HVE3CNtYFrWmRYCug23u8Ii/tPIrihld6i4Q/SzoCqipchIiR4g4sSO6JeMD90kX zi72/afNUq63qUeSB1vn8hBAQLj/NJE7TvHSKcYbVpoPCmjy04RUt6QtOs7zoxrMQYvA6y6jZ5iC FVZKAJiWCCdIyEvYfAYABrTqTHnrT4kEg8LiZyQIRX8hAXVIOSIe2GVyogylpKMHphgeIc1IEmRK IhEkgTUjYXHbrEHwV5fGLXuimiY65tS72efV2PezpeaaQpZUrZ2lDYZenRYPxpun29XodZxjRx5N 0cNy9FLDHfMEMgOzWw9HdDJd4Qq7hpkC7qIDns1pVlBy5Dpuwq5kyRlKM7oM/rIzaRpYvbeRVoHq ykGbqyd8ZsLXRq1oTlBM1EGH6TGVYJyhMUsDZaHSUX3FuvS3E7hrawaEFLZE1zEELEKDGkwY0A+1 cnFTmHBejrCOCe7DHQPo2l8yGOdHKG6Ro1WWFOtojPCMmpHrppbbiFXjo+Zsn6LhebRX6rrySPAT RqyCNR1n3gjJWiyQcGCuBMsyd8AqY+M2HKcD7C60M+zbhsDjVOYltYifLN/C3QkyCHavs8N5gc5S 7hTgujgzvJtsPWOuBD7VVVVVVVVVVVVU9JnUwpJ8YaKJslPZ+QXcAPTDib7iZSoooopxRSCYtRpF oTEkw49K4T49QOKSoqTUCCG2QwgwGINlAtRlS2g6PqMqIHBB9ghCllmgIvMK439ySNgXU/U1R4O+ jHb3TN7mC8flSlbiz5zzEzyGHj6a82nZ9AjssnWsy1wrGRDpulUzVTwj03JLuKCV6n2rtMkEPLQQ 2uaLpxfN4963LNwcHOlEaaB0zvGpXBIRayKpCoJadH0Rs87VRx8UymF1I45rAxN2BGWFRxQdYQUi wQDGYtZKeMrmMtjOkyV4MIaBedI1B1sAchIC1JBHYYVJUKbvU34usoUjiU2zw9EG3aWArTWhUBGu 8HSaJQoARKFI0otA8h6e4g5SVkRh52L60uNDE3Q1vUrJAZPw91ma+KpmKfqssj+X6PJuawpmwXRY 74LZE71BUsgFRB4RY29MIxZQUxNIMGo+n5unRufzvXgJrgyJId6SdsyAV2tFioKI0KiduEqh4yeH s17nwhPMhJt4UIJvOT6iW5sBj7hwwjphBZ8XdhhOjYaYCAFo5fMSGyoQ4YrIhVCpQbzPf8nzFcMM aVPq3Lsqr6y6PiQ9iJcOgS7SAlVD2n5TF4ohxJLjdFDnHsGD191AHpsOqqg/0/OUQD9EMCF0Gk0B BuhSB64tkV2niiUPqF33fQbCqWBvO45rkvgPhFPgUDvuvITTHOFJslQO46r35dKyNqFbbCx2VElK efZyHo+CjNvMM45NjdoIknCGR4G5Y556ArdCgfNfKd8rZiOxovQmGxgEPRKAKqYuyyewhAFVsNK6 zvL6rzIutRhqYeL23bbVKiyRE6CftlJDXVDq9o8wMBINDNzWn4s4lcPARGjFPGdB74Gg6Ra8Ccvv HG5v6l70F0FAXmkqDI+KfKiB6gP3puNaBa+Q7j2GfTOl24kNJSiBSfIecSZAeoXIms0ZjjnIJcyv RgLNL2/HEvUbj68qPxh90Ax4rUuXgYT3PiHeSEL5kyR5itxe22wbaDB83EiPmR1fDsO13ski4SiQ s8gvzmYtBTlMi57o/EYG0enXvHQWWYQ8XGTmSBmDauU44tl62ZheuY6Vh8dQsWKnekiDstIO1d3A ktC2GR0nSfIXYrkE2hsZwNp2nT2lVVG1HNp3I0mG4+cmkv0u++A9LR24Gs2zJqiVk0mY8Ef3k/MS iEEDXiPHcIkqSnoPEvHHHkwrEQkbDE5VzrI3nmLBJFTvI0HVM6synSYEI7iRQ0HKdRhYJAfmZIqe jkB8/1rAlg22wjxkyKFvHw8uFUD5iZuRaAsEPYKQAGRB2Am5ClbbEnWCV3SWJaUURBiSkJC6TpNx VIxPSegvMywnVZygLTMrIGRcIITlZmLMKRQTmCNxyHkaRaTWT4GtZgkaJGRuNRcJI2cRttjbarqb joNLwGgmo3Paajw8WL4DYUO7pR9KHiKj5E/2JtPzN/3hJZNQYcKsSO6cFp/+LuSKcKEgWWT59g== --===============5989403677333247201==--