From: Alexander Nozdrin Date: November 29 2010 2:13pm Subject: bzr push into mysql-trunk-bugfixing branch (alexander.nozdrin:3390 to 3391) Bug#27480 List-Archive: http://lists.mysql.com/commits/125351 X-Bug: 27480 Message-Id: <201011291444.oASLoEmb016978@acsinet15.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3391 Alexander Nozdrin 2010-11-29 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_db.cc 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 3390 Luis Soares 2010-11-29 [merge] Manual merge: mysql-trunk --> mysql-trunk-bugfixing Conflicts ========= Contents conflict in libmysqld/Makefile.am ** Text conflict in mysql-test/suite/binlog/t/disabled.def ** Resolved by removing the file (autotools were removed from trunk-bugfixing some time ago and the changes were not yet in trunk) added: mysql-test/collections/mysql-next-mr-wl2540.push mysql-test/collections/mysql-trunk.daily mysql-test/collections/mysql-trunk.weekly mysql-test/include/have_binlog_checksum_off.inc mysql-test/suite/binlog/r/binlog_checksum.result mysql-test/suite/binlog/t/binlog_checksum.test mysql-test/suite/rpl/extension/README.checksum mysql-test/suite/rpl/extension/checksum.pl mysql-test/suite/rpl/r/rpl_checksum.result mysql-test/suite/rpl/r/rpl_checksum_cache.result mysql-test/suite/rpl/r/rpl_corruption.result mysql-test/suite/rpl/t/rpl_checksum-master.opt mysql-test/suite/rpl/t/rpl_checksum.test mysql-test/suite/rpl/t/rpl_checksum_cache.test mysql-test/suite/rpl/t/rpl_corruption-master.opt mysql-test/suite/rpl/t/rpl_corruption-slave.opt mysql-test/suite/rpl/t/rpl_corruption.test mysql-test/suite/sys_vars/r/binlog_checksum_basic.result mysql-test/suite/sys_vars/r/master_verify_checksum_basic.result mysql-test/suite/sys_vars/r/slave_sql_verify_checksum_basic.result mysql-test/suite/sys_vars/t/binlog_checksum_basic.test mysql-test/suite/sys_vars/t/master_verify_checksum_basic.test mysql-test/suite/sys_vars/t/slave_sql_verify_checksum_basic.test modified: client/mysqlbinlog.cc libmysqld/CMakeLists.txt mysql-test/collections/default.experimental mysql-test/extra/binlog_tests/binlog.test mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test mysql-test/extra/rpl_tests/rpl_change_master.test mysql-test/extra/rpl_tests/rpl_conflicts.test mysql-test/extra/rpl_tests/rpl_flsh_tbls.test mysql-test/extra/rpl_tests/rpl_reset_slave.test mysql-test/extra/rpl_tests/rpl_start_stop_slave.test mysql-test/include/mtr_warnings.sql mysql-test/r/mysqld--help-notwin.result mysql-test/r/mysqld--help-win.result mysql-test/suite/binlog/r/binlog_killed.result mysql-test/suite/binlog/r/binlog_old_versions.result mysql-test/suite/binlog/r/binlog_row_binlog.result mysql-test/suite/binlog/r/binlog_stm_binlog.result mysql-test/suite/binlog/t/binlog_killed.test mysql-test/suite/binlog/t/binlog_old_versions.test mysql-test/suite/rpl/r/rpl_change_master.result mysql-test/suite/rpl/r/rpl_change_master_crash_safe.result mysql-test/suite/rpl/r/rpl_heartbeat_basic.result mysql-test/suite/rpl/r/rpl_rotate_logs.result mysql-test/suite/rpl/r/rpl_row_conflicts.result mysql-test/suite/rpl/r/rpl_server_uuid.result mysql-test/suite/rpl/t/disabled.def mysql-test/suite/rpl/t/rpl_change_master.test mysql-test/suite/rpl/t/rpl_heartbeat_basic.test mysql-test/suite/rpl/t/rpl_known_bugs_detection.test mysql-test/suite/rpl/t/rpl_rotate_logs.test mysql-test/suite/rpl/t/rpl_row_ignorable_event.test mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test mysql-test/suite/rpl/t/rpl_server_uuid.test mysql-test/suite/rpl_ndb/t/rpl_ndb_multi.test mysql-test/suite/sys_vars/t/all_vars.test mysql-test/t/mysqlbinlog2.test sql/binlog.cc sql/binlog.h sql/log.cc sql/log_event.cc sql/log_event.h sql/mysqld.cc sql/mysqld.h sql/rpl_master.cc sql/rpl_mi.cc sql/rpl_mi.h sql/rpl_rli.cc sql/rpl_slave.cc sql/rpl_utility.cc sql/share/errmsg-utf8.txt sql/sql_binlog.cc sql/sql_class.h sql/sys_vars.cc sql/sys_vars.h === modified file 'mysql-test/r/handler_myisam.result' --- a/mysql-test/r/handler_myisam.result 2010-11-18 16:34:56 +0000 +++ b/mysql-test/r/handler_myisam.result 2010-11-29 14:13:07 +0000 @@ -1858,4 +1858,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-11-17 15:23:17 +0000 +++ b/mysql-test/r/merge.result 2010-11-29 14:13:07 +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-08-30 06:38:09 +0000 +++ b/mysql-test/r/temp_table.result 2010-11-29 14:13:07 +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-11-29 14:13:07 +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-26 09:10:59 +0000 +++ b/mysql-test/t/merge.test 2010-11-29 14:13:07 +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-11-29 14:13:07 +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-11-29 11:28:55 +0000 +++ b/sql/sp_head.cc 2010-11-29 14:13:07 +0000 @@ -2952,6 +2952,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) @@ -4175,6 +4178,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-11-18 16:34:56 +0000 +++ b/sql/sql_admin.cc 2010-11-29 14:13:07 +0000 @@ -88,8 +88,7 @@ static int prepare_for_repair(THD *thd, MDL_EXCLUSIVE, MDL_TRANSACTION); 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); @@ -684,6 +714,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( @@ -710,8 +749,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; @@ -824,7 +863,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. @@ -853,8 +891,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); } @@ -890,8 +926,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)); } @@ -917,8 +955,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)); } @@ -929,13 +969,12 @@ bool Sql_cmd_analyze_table::execute(THD thr_lock_type lock_type = TL_READ_NO_INSERT; DBUG_ENTER("Sql_cmd_analyze_table::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, &thd->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 && !thd->lex->no_write_to_binlog) { @@ -947,7 +986,6 @@ bool Sql_cmd_analyze_table::execute(THD thd->lex->select_lex.table_list.first= first_table; thd->lex->query_tables= first_table; -error: DBUG_RETURN(res); } @@ -965,7 +1003,9 @@ bool Sql_cmd_check_table::execute(THD *t thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &thd->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); thd->lex->select_lex.table_list.first= first_table; @@ -989,8 +1029,9 @@ bool Sql_cmd_optimize_table::execute(THD res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? mysql_recreate_table(thd, first_table) : mysql_admin_table(thd, first_table, &thd->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 && !thd->lex->no_write_to_binlog) { @@ -1018,10 +1059,12 @@ bool Sql_cmd_repair_table::execute(THD * goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_admin_table(thd, first_table, &thd->lex->check_opt, "repair", - TL_WRITE, 1, + TL_WRITE, + FALSE, SELECT_ACL| INSERT_ACL, + TRUE, test(thd->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 && !thd->lex->no_write_to_binlog) === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2010-11-23 22:37:59 +0000 +++ b/sql/sql_base.cc 2010-11-29 14:13:07 +0000 @@ -2557,46 +2557,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) { @@ -2611,6 +2607,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); @@ -2622,62 +2626,10 @@ bool open_table(THD *thd, TABLE_LIST *ta TMP_TABLE_KEY_EXTRA); /* - 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 && @@ -2736,6 +2688,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, @@ -2773,7 +2726,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. @@ -2785,10 +2738,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)) { @@ -3997,8 +3947,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, @@ -4014,8 +3963,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, @@ -4344,6 +4292,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)++; @@ -4353,6 +4320,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. @@ -4454,6 +4441,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) @@ -4464,6 +4452,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. */ @@ -4551,18 +4541,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) && @@ -4630,35 +4619,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)))) - { - /* - 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; + 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))) + { + 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; @@ -4837,6 +4825,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; } @@ -4883,6 +4875,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; } @@ -4913,6 +4909,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) { @@ -5942,6 +5943,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-11-23 22:37:59 +0000 +++ b/sql/sql_base.h 2010-11-29 14:13:07 +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. */ @@ -139,7 +138,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, @@ -269,6 +267,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. */ @@ -572,6 +573,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-11-29 11:28:55 +0000 +++ b/sql/sql_class.h 2010-11-29 14:13:07 +0000 @@ -3699,6 +3699,18 @@ public: */ #define CF_WRITE_RPL_INFO_COMMAND (1U << 12) +/** + 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_db.cc' --- a/sql/sql_db.cc 2010-11-18 16:34:56 +0000 +++ b/sql/sql_db.cc 2010-11-29 14:13:07 +0000 @@ -823,8 +823,7 @@ bool mysql_rm_db(THD *thd,char *db,bool } /* Lock all tables and stored routines about to be dropped. */ - 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) || lock_db_routines(thd, db)) { thd->pop_internal_handler(); === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2010-11-18 16:34:56 +0000 +++ b/sql/sql_handler.cc 2010-11-29 14:13:07 +0000 @@ -287,12 +287,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-11-29 03:17:40 +0000 +++ b/sql/sql_insert.cc 2010-11-29 14:13:07 +0000 @@ -3782,8 +3782,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 @@ -3793,7 +3792,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-11-29 11:28:55 +0000 +++ b/sql/sql_parse.cc 2010-11-29 14:13:07 +0000 @@ -23,7 +23,7 @@ // set_handler_table_locks, // 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 @@ -43,7 +43,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 @@ -370,7 +369,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; @@ -446,6 +445,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) @@ -1200,6 +1246,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; @@ -2017,6 +2066,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: @@ -2089,7 +2147,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; @@ -2318,9 +2376,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; @@ -2358,9 +2427,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; @@ -2518,6 +2584,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 */ /* @@ -2662,6 +2729,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. @@ -3135,6 +3209,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 +3640,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. */ @@ -4537,6 +4628,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)) && @@ -4958,10 +5052,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(), @@ -4969,6 +5063,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-11-26 15:20:05 +0000 +++ b/sql/sql_prepare.cc 2010-11-29 14:13:07 +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 */ @@ -1715,6 +1716,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); @@ -1778,6 +1788,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; @@ -1964,6 +1980,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: @@ -2094,6 +2124,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-11-18 16:34:56 +0000 +++ b/sql/sql_rename.cc 2010-11-29 14:13:07 +0000 @@ -139,8 +139,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-11-29 11:28:55 +0000 +++ b/sql/sql_show.cc 2010-11-29 14:13:07 +0000 @@ -3019,11 +3019,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"); @@ -3628,6 +3635,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-11-29 11:28:55 +0000 +++ b/sql/sql_table.cc 2010-11-29 14:13:07 +0000 @@ -2048,8 +2048,8 @@ bool mysql_rm_table(THD *thd,TABLE_LIST { 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(true); for (table= tables; table; table= table->next_local) tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name, @@ -5935,8 +5935,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. */ @@ -6553,14 +6551,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 @@ -7274,13 +7270,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. */ @@ -7318,13 +7307,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); @@ -7422,11 +7414,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-21 11:34:17 +0000 +++ b/sql/sql_truncate.cc 2010-11-29 14:13:07 +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 Sql_cmd_truncate_table::handler_trun */ /* 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 Sql_cmd_truncate_table::handler_trun 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 Sql_cmd_truncate_table::lock_table( /* 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 Sql_cmd_truncate_table::lock_table( bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) { int error; - TABLE *table; bool binlog_stmt; DBUG_ENTER("Sql_cmd_truncate_table::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-11-18 16:34:56 +0000 +++ b/sql/sql_view.cc 2010-11-29 14:13:07 +0000 @@ -441,6 +441,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)) @@ -1639,8 +1645,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) No bundle (reason: useless for push emails).