From: Dmitry Lenev Date: December 22 2010 3:57pm Subject: bzr push into mysql-trunk-bugfixing branch (Dmitry.Lenev:3401 to 3402) Bug#27480 List-Archive: http://lists.mysql.com/commits/127516 X-Bug: 27480 Message-Id: <20101222155718.13F352F95B5@mockturtle> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3402 Dmitry Lenev 2010-12-22 Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). Review fixes in progress. Final (almost) batch of fixes. modified: mysql-test/r/alter_table.result mysql-test/r/handler_myisam.result mysql-test/r/temp_table.result mysql-test/suite/innodb/r/innodb_mysql.result mysql-test/suite/innodb/t/innodb_mysql.test mysql-test/suite/rpl/r/rpl_create_if_not_exists.result mysql-test/suite/rpl/t/rpl_create_if_not_exists.test mysql-test/t/alter_table.test mysql-test/t/handler_myisam.test mysql-test/t/temp_table.test sql/log_event.cc sql/sql_admin.cc sql/sql_base.cc sql/sql_base.h sql/sql_class.h sql/sql_handler.cc sql/sql_parse.cc sql/sql_partition_admin.cc sql/sql_show.cc sql/sql_table.cc sql/sql_truncate.cc 3401 Dmitry Lenev 2010-12-14 Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). Review fixes in progress. Polish handling of OT_TEMPORARY_ONLY flag and streamline process of table opening. modified: sql/sql_base.cc === modified file 'mysql-test/r/alter_table.result' --- a/mysql-test/r/alter_table.result 2010-08-30 06:38:09 +0000 +++ b/mysql-test/r/alter_table.result 2010-12-22 15:23:28 +0000 @@ -1383,3 +1383,14 @@ ALTER TABLE t1 CHANGE a id INT; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 DROP TABLE t1; +# +# Additional coverage for refactoring which is made as part +# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +# to allow temp table operations". +# +# At some point the below test case failed on assertion. +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM; +ALTER TABLE t1 DISCARD TABLESPACE; +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; === modified file 'mysql-test/r/handler_myisam.result' --- a/mysql-test/r/handler_myisam.result 2010-11-29 14:13:07 +0000 +++ b/mysql-test/r/handler_myisam.result 2010-12-22 15:23:28 +0000 @@ -1859,15 +1859,20 @@ a b HANDLER t1 CLOSE; DROP TABLE t1; # -# Bug#27480 +# Additional coverage for refactoring which is made as part +# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +# to allow temp table operations". # +# Check that DDL on temporary table properly closes HANDLER cursors +# for this table belonging to the same connection. CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; # -- CREATE TABLE HANDLER t1 OPEN; -CREATE TABLE t2 SELECT * FROM t1; +CREATE TEMPORARY TABLE IF NOT EXISTS t1 SELECT 1 AS f1; +Warnings: +Note 1050 Table 't1' already exists HANDLER t1 READ FIRST; ERROR 42S02: Unknown table 't1' in HANDLER -DROP TABLE t2; # -- REPAIR TABLE HANDLER t1 OPEN; REPAIR TABLE t1; @@ -1901,6 +1906,21 @@ HANDLER t1 OPEN; ALTER TABLE t1 ADD COLUMN b INT; HANDLER t1 READ FIRST; ERROR 42S02: Unknown table 't1' in HANDLER +# -- CREATE INDEX +HANDLER t1 OPEN; +CREATE INDEX b ON t1 (b); +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- DROP INDEX +HANDLER t1 OPEN; +DROP INDEX b ON t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER +# -- TRUNCATE TABLE +HANDLER t1 OPEN; +TRUNCATE TABLE t1; +HANDLER t1 READ FIRST; +ERROR 42S02: Unknown table 't1' in HANDLER # -- DROP TABLE HANDLER t1 OPEN; DROP TABLE t1; === modified file 'mysql-test/r/temp_table.result' --- a/mysql-test/r/temp_table.result 2010-11-29 14:13:07 +0000 +++ b/mysql-test/r/temp_table.result 2010-12-22 15:23:28 +0000 @@ -223,6 +223,10 @@ CREATE TEMPORARY TABLE bug48067.t1 (c1 i DROP DATABASE bug48067; DROP TEMPORARY table bug48067.t1; End of 5.1 tests +# +# Test that admin statements work for temporary tables. +# +DROP TABLE IF EXISTS t1,t2; CREATE TEMPORARY TABLE t1(a INT); CREATE TEMPORARY TABLE t2(b INT); CREATE TEMPORARY TABLE t3(c INT); @@ -266,3 +270,4 @@ Table Op Msg_type Msg_text test.t1 repair status OK test.t2 repair status OK test.t3 repair status OK +DROP TABLES t1, t2, t3; === modified file 'mysql-test/suite/innodb/r/innodb_mysql.result' --- a/mysql-test/suite/innodb/r/innodb_mysql.result 2010-11-26 13:46:21 +0000 +++ b/mysql-test/suite/innodb/r/innodb_mysql.result 2010-12-22 15:23:28 +0000 @@ -2830,4 +2830,17 @@ PACK_KEYS=0; CREATE INDEX a ON t1 (a); CREATE INDEX c on t1 (c); DROP TABLE t1; +# +# Additional coverage for refactoring which is made as part +# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +# to allow temp table operations". +# +# Check that OPTIMIZE table works for temporary InnoDB tables. +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +DROP TABLE t1; End of 6.0 tests === modified file 'mysql-test/suite/innodb/t/innodb_mysql.test' --- a/mysql-test/suite/innodb/t/innodb_mysql.test 2010-11-23 11:04:47 +0000 +++ b/mysql-test/suite/innodb/t/innodb_mysql.test 2010-12-22 15:23:28 +0000 @@ -992,4 +992,19 @@ CREATE INDEX c on t1 (c); DROP TABLE t1; + +--echo # +--echo # Additional coverage for refactoring which is made as part +--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +--echo # to allow temp table operations". +--echo # +--echo # Check that OPTIMIZE table works for temporary InnoDB tables. +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB; +OPTIMIZE TABLE t1; +DROP TABLE t1; + + --echo End of 6.0 tests === modified file 'mysql-test/suite/rpl/r/rpl_create_if_not_exists.result' --- a/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result 2010-08-30 08:40:42 +0000 +++ b/mysql-test/suite/rpl/r/rpl_create_if_not_exists.result 2010-12-22 15:23:28 +0000 @@ -126,3 +126,17 @@ show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info DROP VIEW v1; DROP TABLE t1, t2; +# +# Test case which has failed on assertion after refactoring which was +# made as part of fix for bug #27480 "Extend CREATE TEMPORARY TABLES +# privilege to allow temp table operations". +# +CREATE TEMPORARY TABLE t1 (id int); +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +# The below statement should succeed with warning and +# should not crash due to failing assertion. +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +Warnings: +Note 1050 Table 't2' already exists +# Clean-up. +DROP TABLE t1, t2; === modified file 'mysql-test/suite/rpl/t/rpl_create_if_not_exists.test' --- a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test 2010-08-30 08:40:42 +0000 +++ b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test 2010-12-22 15:23:28 +0000 @@ -173,4 +173,21 @@ DROP VIEW v1; DROP TABLE t1, t2; + +--echo # +--echo # Test case which has failed on assertion after refactoring which was +--echo # made as part of fix for bug #27480 "Extend CREATE TEMPORARY TABLES +--echo # privilege to allow temp table operations". +--echo # +CREATE TEMPORARY TABLE t1 (id int); +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +--echo # The below statement should succeed with warning and +--echo # should not crash due to failing assertion. +CREATE TABLE IF NOT EXISTS t2 LIKE t1; +--echo # Clean-up. +DROP TABLE t1, t2; +sync_slave_with_master; +connection master; + + source include/master-slave-end.inc; === modified file 'mysql-test/t/alter_table.test' --- a/mysql-test/t/alter_table.test 2010-07-26 09:22:38 +0000 +++ b/mysql-test/t/alter_table.test 2010-12-22 15:23:28 +0000 @@ -1144,3 +1144,18 @@ INSERT INTO t1 VALUES (1, 1), (2, 2); ALTER TABLE t1 CHANGE a id INT; --disable_info DROP TABLE t1; + + +--echo # +--echo # Additional coverage for refactoring which is made as part +--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +--echo # to allow temp table operations". +--echo # +--echo # At some point the below test case failed on assertion. +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM; +--error ER_ILLEGAL_HA +ALTER TABLE t1 DISCARD TABLESPACE; +DROP TABLE t1; === modified file 'mysql-test/t/handler_myisam.test' --- a/mysql-test/t/handler_myisam.test 2010-11-29 14:13:07 +0000 +++ b/mysql-test/t/handler_myisam.test 2010-12-22 15:23:28 +0000 @@ -98,19 +98,21 @@ DROP TABLE t1; --echo # ---echo # Bug#27480 +--echo # Additional coverage for refactoring which is made as part +--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +--echo # to allow temp table operations". --echo # +--echo # Check that DDL on temporary table properly closes HANDLER cursors +--echo # for this table belonging to the same connection. CREATE TEMPORARY TABLE t1 AS SELECT 1 AS f1; --echo # -- CREATE TABLE HANDLER t1 OPEN; -CREATE TABLE t2 SELECT * FROM t1; +CREATE TEMPORARY TABLE IF NOT EXISTS t1 SELECT 1 AS f1; --error ER_UNKNOWN_TABLE HANDLER t1 READ FIRST; -DROP TABLE t2; - --echo # -- REPAIR TABLE HANDLER t1 OPEN; REPAIR TABLE t1; @@ -141,6 +143,24 @@ ALTER TABLE t1 ADD COLUMN b INT; --error ER_UNKNOWN_TABLE HANDLER t1 READ FIRST; +--echo # -- CREATE INDEX +HANDLER t1 OPEN; +CREATE INDEX b ON t1 (b); +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- DROP INDEX +HANDLER t1 OPEN; +DROP INDEX b ON t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + +--echo # -- TRUNCATE TABLE +HANDLER t1 OPEN; +TRUNCATE TABLE t1; +--error ER_UNKNOWN_TABLE +HANDLER t1 READ FIRST; + --echo # -- DROP TABLE HANDLER t1 OPEN; DROP TABLE t1; === modified file 'mysql-test/t/temp_table.test' --- a/mysql-test/t/temp_table.test 2010-11-29 14:13:07 +0000 +++ b/mysql-test/t/temp_table.test 2010-12-22 15:23:28 +0000 @@ -252,8 +252,12 @@ DROP TEMPORARY table bug48067.t1; --echo End of 5.1 tests -# Check admin statements. - +--echo # +--echo # Test that admin statements work for temporary tables. +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1,t2; +--enable_warnings CREATE TEMPORARY TABLE t1(a INT); CREATE TEMPORARY TABLE t2(b INT); CREATE TEMPORARY TABLE t3(c INT); @@ -288,3 +292,5 @@ INSERT INTO t2 VALUES (11), (12), (13); INSERT INTO t3 VALUES (101), (102), (103); REPAIR TABLE t1, t2, t3; + +DROP TABLES t1, t2, t3; === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2010-11-29 16:55:45 +0000 +++ b/sql/log_event.cc 2010-12-22 15:23:28 +0000 @@ -5302,7 +5302,8 @@ int Load_log_event::do_apply_event(NET* update it inside mysql_load(). */ List tmp_list; - if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list, + if (open_temporary_table_list(thd, &tables) || + mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list, handle_dup, ignore, net != 0)) thd->is_slave_error= 1; if (thd->cuted_fields) === modified file 'sql/sql_admin.cc' --- a/sql/sql_admin.cc 2010-12-14 09:15:37 +0000 +++ b/sql/sql_admin.cc 2010-12-22 15:23:28 +0000 @@ -17,7 +17,6 @@ #include "keycaches.h" // get_key_cache #include "sql_base.h" // Open_table_context #include "lock.h" // MYSQL_OPEN_* -#include "sql_handler.h" // mysql_ha_rm_tables #include "partition_element.h" // PART_ADMIN #include "sql_partition.h" // set_part_state #include "transaction.h" // trans_rollback_stmt @@ -565,6 +564,13 @@ static bool mysql_admin_table(THD* thd, HA_ADMIN_NEEDS_ALTER)) { DBUG_PRINT("admin", ("recreating table")); + /* + Temporary table are always created by current server so they never + require upgrade. So we don't need to pre-open them before calling + mysql_recreate_table(). + */ + DBUG_ASSERT(! table->table->s->tmp_table); + trans_rollback_stmt(thd); trans_rollback(thd); close_thread_tables(thd); @@ -723,7 +729,9 @@ send_result_message: *save_next_global= table->next_global; table->next_local= table->next_global= 0; tmp_disable_binlog(thd); // binlogging is done by caller if wanted - result_code= mysql_recreate_table(thd, table); + /* Don't forget to pre-open temporary tables. */ + result_code= (open_temporary_table_list(thd, table) || + mysql_recreate_table(thd, table)); reenable_binlog(thd); /* mysql_recreate_table() can push OK or ERROR. @@ -737,14 +745,15 @@ send_result_message: trans_commit(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); - if (!result_code && // recreation went ok - !table->table) // not a temporary table opened above + /* Clear references to TABLE and MDL_ticket after releasing them. */ + table->table= NULL; + table->mdl_request.ticket= NULL; + if (!result_code) // recreation went ok { - /* Clear the ticket released above. */ - table->mdl_request.ticket= NULL; DEBUG_SYNC(thd, "ha_admin_open_ltable"); table->mdl_request.set_type(MDL_SHARED_WRITE); - if ((table->table= open_ltable(thd, table, lock_type, 0))) + if (!open_temporary_table_list(thd, table) && + (table->table= open_n_lock_single_table(thd, table, lock_type, 0))) { result_code= table->table->file->ha_analyze(thd, check_opt); if (result_code == HA_ADMIN_ALREADY_DONE) === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2010-12-14 15:31:57 +0000 +++ b/sql/sql_base.cc 2010-12-22 15:23:28 +0000 @@ -2621,8 +2621,7 @@ bool open_table(THD *thd, TABLE_LIST *ta if (thd->killed) DBUG_RETURN(TRUE); - key_length= (create_table_def_key(thd, key, table_list, 1) - - TMP_TABLE_KEY_EXTRA); + key_length= create_table_def_key(thd, key, table_list, 0); /* If we're in pre-locked or LOCK TABLES mode, let's try to find the @@ -4303,7 +4302,7 @@ open_and_process_table(THD *thd, LEX *le (TABLE_LIST::table is not NULL), that TABLE object must be a pre-opened temporary table. */ - DBUG_ASSERT(is_temporary_table(tables->table)); + DBUG_ASSERT(is_temporary_table(tables)); } else if (tables->open_type == OT_TEMPORARY_ONLY) { @@ -5973,6 +5972,9 @@ static void update_field_dependencies(TH of this thread. Temporary tables are thread-local and "shadow" base tables with the same name. + @note In most cases one should use open_temporary_tables() instead + of this call. + @note One should finalize process of opening temporary table for table list element by calling open_and_process_table(). This function is responsible for table version checking and handling of merge @@ -5998,16 +6000,21 @@ bool open_temporary_table(THD *thd, TABL */ DBUG_ASSERT(tl->table == NULL); + /* + This function should not be called for cases when derived or I_S + tables can be met since table list elements for such tables can + have invalid db or table name. + Instead open_temporary_table_list() should be used. + */ + DBUG_ASSERT(!tl->derived && !tl->schema_table); + if (tl->open_type == OT_BASE_ONLY) { DBUG_PRINT("info", ("skip_temporary is set")); 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); + TABLE *table= find_temporary_table(thd, tl); if (!table) { @@ -6050,12 +6057,33 @@ bool open_temporary_table(THD *thd, TABL } +/** + Pre-open temporary tables corresponding to table list elements. + + @note One should finalize process of opening temporary tables + by calling open_tables(). This function is responsible + for table version checking and handling of merge tables. + + @return Error status. + @retval FALSE On success. If a temporary tables exists for the + given element, tl->table is set. + @retval TRUE On error. my_error() has been called. +*/ + bool open_temporary_table_list(THD *thd, TABLE_LIST *tl_list) { DBUG_ENTER("open_temporary_table_list"); for (TABLE_LIST *tl= tl_list; tl; tl= tl->next_global) { + if (tl->derived || tl->schema_table) + { + /* + Derived and I_S tables will be handled by a later call to open_tables(). + */ + continue; + } + if (open_temporary_table(thd, tl)) DBUG_RETURN(TRUE); } === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2010-12-14 09:15:37 +0000 +++ b/sql/sql_base.h 2010-12-22 15:23:28 +0000 @@ -572,27 +572,12 @@ 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. + Check if a TABLE_LIST instance represents a pre-opened temporary table. */ inline bool is_temporary_table(TABLE_LIST *tl) { - return tl->table ? is_temporary_table(tl->table) : FALSE; + return tl->table ? (tl->table->s->tmp_table != NO_TMP_TABLE) : FALSE; } === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2010-12-06 10:36:38 +0000 +++ b/sql/sql_class.h 2010-12-22 15:23:28 +0000 @@ -3703,7 +3703,7 @@ public: #define CF_PREOPEN_TMP_TABLES (1U << 10) /** - Identfies statements for which open handlers should be closed in the + Identifies statements for which open handlers should be closed in the beginning of the statement. */ #define CF_HA_CLOSE (1U << 11) === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2010-12-14 09:15:37 +0000 +++ b/sql/sql_handler.cc 2010-12-22 15:23:28 +0000 @@ -287,7 +287,11 @@ bool mysql_ha_open(THD *thd, TABLE_LIST */ DBUG_ASSERT(! hash_tables->table); - error= open_temporary_table(thd, hash_tables); + /* + TODO/FIXME: In the upcoming patch we somehow should handle + situation with privilege check for temporary table. + */ + error= open_temporary_table_list(thd, hash_tables); if (!error) error= open_tables(thd, &hash_tables, &counter, 0); === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-12-14 09:15:37 +0000 +++ b/sql/sql_parse.cc 2010-12-22 15:23:28 +0000 @@ -369,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; @@ -455,7 +455,6 @@ void init_update_queries(void) 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; @@ -484,9 +483,11 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES; /* - DDL statements should start with closing opened handlers. - */ + DDL statements that should start with closing opened handlers. + We use this flag only for statements for which open HANDLERs + have to be closed before emporary tables are pre-opened. + */ 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; @@ -1252,7 +1253,7 @@ 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_temporary_table(thd, &table_list)) + if (open_temporary_table_list(thd, &table_list)) break; if (check_table_access(thd, SELECT_ACL, &table_list, @@ -2072,9 +2073,25 @@ mysql_execute_command(THD *thd) DEBUG_SYNC(thd,"before_execute_sql_command"); #endif + /* + Close tables open by HANDLERs before executing DDL statement + which is going to affect those tables. + + This should happen before temporary tables are pre-opened as + otherwise we will get errors about attempt to re-open tables + if table to be changed is open through HANDLER. + + Note that even although this is done before any privilege + checks there is no security problem here as closing open + HANDLER doesn't require any privileges anyway. + */ if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE) mysql_ha_rm_tables(thd, all_tables); + /* + Pre-open temporary tables to simplify privilege checking + for statements which need this. + */ if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) { if (open_temporary_table_list(thd, all_tables)) @@ -2382,6 +2399,10 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + /* + Pre-open temporary tables from UNION clause to simplify privilege + checking for them. + */ if (lex->create_info.merge_list.elements) { if (open_temporary_table_list( @@ -3218,12 +3239,10 @@ end_with_restore_list: 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(). + because LOCK TABLES calls close_thread_tables() as a first thing + (it's called from unlock_locked_tables() above). So even if + CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened + in a usual way, they would have been closed. */ if (open_temporary_table_list(thd, all_tables)) @@ -4630,6 +4649,7 @@ bool check_single_table_access(THD *thd, &all_tables->grant.m_internal, 0, no_errors)) goto deny; + /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && @@ -4953,6 +4973,12 @@ static bool check_show_access(THD *thd, DBUG_ASSERT(dst_table); + /* + TODO/FIXME: In the upcoming patch we somehow should handle + situation when table in question is a temporary + table. + */ + if (check_access(thd, SELECT_ACL, dst_table->db, &dst_table->grant.privilege, &dst_table->grant.m_internal, === modified file 'sql/sql_partition_admin.cc' --- a/sql/sql_partition_admin.cc 2010-11-16 00:55:42 +0000 +++ b/sql/sql_partition_admin.cc 2010-12-22 15:23:28 +0000 @@ -20,7 +20,6 @@ #include "sql_cmd.h" // Sql_cmd #include "sql_alter.h" // Sql_cmd_alter_table #include "sql_partition.h" // struct partition_info, etc. -#include "sql_handler.h" // mysql_ha_rm_tables #include "sql_base.h" // open_and_lock_tables, etc #include "debug_sync.h" // DEBUG_SYNC #include "sql_truncate.h" // mysql_truncate_table, @@ -492,9 +491,6 @@ bool Sql_cmd_alter_table_exchange_partit partition_name= alter_info->partition_names.head(); - /* Clear open tables from the threads table handler cache */ - mysql_ha_rm_tables(thd, table_list); - /* Don't allow to exchange with log table */ swap_table_list= table_list->next_local; if (check_if_log_table(swap_table_list->db_length, swap_table_list->db, === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2010-12-14 09:15:37 +0000 +++ b/sql/sql_show.cc 2010-12-22 15:23:28 +0000 @@ -3635,8 +3635,6 @@ 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_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-12-14 09:15:37 +0000 +++ b/sql/sql_table.cc 2010-12-22 15:23:28 +0000 @@ -4800,6 +4800,7 @@ bool mysql_create_like_table(THD* thd, T String query(buf, sizeof(buf), system_charset_info); query.length(0); // Have to zero it since constructor doesn't Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); + bool new_table= FALSE; // Whether newly created table is open. /* The condition avoids a crash as described in BUG#48506. Other @@ -4808,14 +4809,20 @@ bool mysql_create_like_table(THD* thd, T */ if (!table->view) { - /* - Here we open the destination table, on which we already have - exclusive metadata lock. This is needed for store_create_info() - to work. The table will be closed by close_thread_table() at - the end of this branch. - */ - if (open_table(thd, table, thd->mem_root, &ot_ctx)) - goto err; + if (!table->table) + { + /* + In order for store_create_info() to work we need to open + destination table if it is not already open (i.e. if it + has not existed before). We don't need acquire metadata + lock in order to do this as we already hold exclusive + lock on this table. The table will be closed by + close_thread_table() at the end of this branch. + */ + if (open_table(thd, table, thd->mem_root, &ot_ctx)) + goto err; + new_table= TRUE; + } int result __attribute__((unused))= store_create_info(thd, table, &query, @@ -4825,13 +4832,16 @@ bool mysql_create_like_table(THD* thd, T if (write_bin_log(thd, TRUE, query.ptr(), query.length())) goto err; - DBUG_ASSERT(thd->open_tables == table->table); - /* - When opening the table, we ignored the locked tables - (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without - risking to close some locked table. - */ - close_thread_table(thd, &thd->open_tables); + if (new_table) + { + DBUG_ASSERT(thd->open_tables == table->table); + /* + When opening the table, we ignored the locked tables + (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table + without risking to close some locked table. + */ + close_thread_table(thd, &thd->open_tables); + } } } else // Case 1 @@ -4854,9 +4864,9 @@ err: static int mysql_discard_or_import_tablespace(THD *thd, TABLE_LIST *table_list, - enum tablespace_op_type tablespace_op) + Alter_info *alter_info) { - TABLE *table; + Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info); my_bool discard; int error; DBUG_ENTER("mysql_discard_or_import_tablespace"); @@ -4868,21 +4878,30 @@ mysql_discard_or_import_tablespace(THD * thd_proc_info(thd, "discard_or_import_tablespace"); - discard= test(tablespace_op == DISCARD_TABLESPACE); + discard= test(alter_info->tablespace_op == DISCARD_TABLESPACE); /* We set this flag so that ha_innobase::open and ::external_lock() do not complain when we lock the table */ thd->tablespace_op= TRUE; + /* + Adjust values of table-level and metadata which was set in parser + for the case general ALTER TABLE. + */ table_list->mdl_request.set_type(MDL_SHARED_WRITE); - if (!(table=open_ltable(thd, table_list, TL_WRITE, 0))) + table_list->lock_type= TL_WRITE; + /* Do not open views. */ + table_list->required_type= FRMTYPE_TABLE; + + if (open_and_lock_tables(thd, table_list, FALSE, 0, + &alter_prelocking_strategy)) { thd->tablespace_op=FALSE; DBUG_RETURN(-1); } - error= table->file->ha_discard_or_import_tablespace(discard); + error= table_list->table->file->ha_discard_or_import_tablespace(discard); thd_proc_info(thd, "end"); @@ -4913,7 +4932,7 @@ err: DBUG_RETURN(0); } - table->file->print_error(error, MYF(0)); + table_list->table->file->print_error(error, MYF(0)); DBUG_RETURN(-1); } @@ -5939,7 +5958,7 @@ bool mysql_alter_table(THD *thd,char *ne if (alter_info->tablespace_op != NO_TABLESPACE_OP) /* Conditionally writes to binlog. */ DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, - alter_info->tablespace_op)); + alter_info)); /* Code below can handle only base tables so ensure that we won't open a view. @@ -7328,7 +7347,7 @@ bool mysql_checksum_table(THD *thd, TABL /* Allow to open real tables only. */ table->required_type= FRMTYPE_TABLE; - if (open_temporary_table(thd, table) || + if (open_temporary_table_list(thd, table) || open_and_lock_tables(thd, table, FALSE, 0)) { t= NULL; === modified file 'sql/sql_truncate.cc' --- a/sql/sql_truncate.cc 2010-11-29 14:13:07 +0000 +++ b/sql/sql_truncate.cc 2010-12-22 15:23:28 +0000 @@ -18,7 +18,6 @@ #include "sql_class.h" // THD #include "sql_base.h" // open_and_lock_tables #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_* flags #include "sql_acl.h" // DROP_ACL No bundle (reason: useless for push emails).