#At file:///home/alik/MySQL/bzr/00/bug27480/mysql-trunk-bugfixing-bug27480/ based on revid:luis.soares@stripped
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
=== 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 <stored function>).
+
+ So, the case might be like this:
+ CREATE TEMPORARY TABLE tmp1(a INT);
+ CREATE TEMPORARY TABLE tmp2(a INT);
+ CREATE TABLE mrg1(a INT) ENGINE=MERGE UNION=(tmp1, tmp2);
+ CREATE FUNCTION f1() RETURNS INT RETURN (SELECT COUNT(*) FROM mrg1);
+ PREPARE stmt1 FROM 'SELECT f1()';
+
+ What's going on is this:
+ - 'tables' are empty for the statement being prepared;
+ - thus, before the "big switch" no temporary table is opened;
+ - after 'f1' is opened, 'mrg1' is added to the prelocking list;
+ - after 'mrg1' is opened, 'tmp1' and 'tmp2' are added to 'tables';
+ - so, here we have not-opened temporary tables 'tmp1' and 'tmp2'
+ in the 'tables' list.
+
+ The thing is that HA_ATTACH_CHILDREN must be called for all merge
+ children during the prepare phase. This is critical because merge
+ children remembers "TABLE_SHARE ref type" and "TABLE_SHARE def version"
+ in the HA_ATTACH_CHILDREN operation.
+
+ If HA_ATTACH_CHILDREN is not called, these attributes are not set.
+ Then, during the first EXECUTE, those attributes need to be updated.
+ That would cause statement re-preparing (because changing those
+ attributes during EXECUTE is caught by THD::m_reprepare_observer).
+ The problem is that since those attributes are not set in merge children,
+ another round of PREPARE will not help. The attributes will be
+ remembered, but as soon as close_thread_tables() is called at the end
+ of PREPARE, this information will be lost again.
+ */
+
+ if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES)
+ {
+ List<TABLE_LIST> new_tl_arr;
+
+ for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global)
+ {
+ if (tl->table)
+ continue;
+
+ if (open_and_process_temporary_table(thd, tl))
+ goto error;
+
+ new_tl_arr.push_back(tl);
+ }
+
+ /*
+ Ensure that HA_ATTACH_CHILDREN has been called for newly added (by
+ prelocking) merge tables.
+ */
+ {
+ List_iterator_fast<TABLE_LIST> new_tl_arr_it(new_tl_arr);
+ TABLE_LIST *tl;
+ while ((tl= new_tl_arr_it++))
+ {
+ if (!tl->table ||
+ tl->table->file->ht->db_type != DB_TYPE_MRG_MYISAM)
+ continue;
+
+ /* MERGE tables need to access parent and child TABLE_LISTs. */
+ DBUG_ASSERT(tl->table->pos_in_table_list == tl);
+
+ if (tl->table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
+ goto error;
+ }
+ }
+ }
+
if (res == 0)
DBUG_RETURN(stmt->is_sql_prepare() ?
FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
=== modified file 'sql/sql_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)
Attachment: [text/bzr-bundle] bzr/alexander.nozdrin@oracle.com-20101129141307-r3tx8bmhtx7pdcn2.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-bugfixing branch (alexander.nozdrin:3391)Bug#27480 | Alexander Nozdrin | 29 Nov |