#At file:///mnt/raid/alik/MySQL/bzr/00/bug27480/mysql-5.5-runtime-bug27480.2/ based on revid:alik@stripped
3120 Alexander Nozdrin 2010-08-20
Bug#27480 (Extend CREATE TEMPORARY TABLES privilege
to allow temp table operations) -- prerequisite patch #4:
- 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_OPEN_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_OPEN_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/sp.result
mysql-test/r/temp_table.result
mysql-test/t/handler_myisam.test
mysql-test/t/merge.test
mysql-test/t/sp.test
mysql-test/t/temp_table.test
sql/lock.cc
sql/log_event_old.cc
sql/sp_head.cc
sql/sql_admin.cc
sql/sql_base.cc
sql/sql_base.h
sql/sql_class.h
sql/sql_delete.cc
sql/sql_handler.cc
sql/sql_insert.cc
sql/sql_parse.cc
sql/sql_prepare.cc
sql/sql_show.cc
sql/sql_table.cc
sql/sql_truncate.cc
sql/sql_update.cc
sql/sql_view.cc
=== modified file 'mysql-test/r/handler_myisam.result'
--- a/mysql-test/r/handler_myisam.result 2010-07-05 11:59:34 +0000
+++ b/mysql-test/r/handler_myisam.result 2010-08-20 16:00:19 +0000
@@ -1847,4 +1847,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-08-18 09:35:41 +0000
+++ b/mysql-test/r/merge.result 2010-08-20 16:00:19 +0000
@@ -2674,10 +2674,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 note The storage engine for the table doesn't support optimize
+ERROR HY000: Can't reopen table: 't1'
DROP TABLE t1;
#
# Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine
=== modified file 'mysql-test/r/sp.result'
--- a/mysql-test/r/sp.result 2010-07-30 15:28:36 +0000
+++ b/mysql-test/r/sp.result 2010-08-20 16:00:19 +0000
@@ -1105,7 +1105,7 @@ select * from v1|
a
3
select * from v1, t1|
-ERROR HY000: Table 't1' was not locked with LOCK TABLES
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
select f4()|
ERROR HY000: Table 't2' was not locked with LOCK TABLES
unlock tables|
=== modified file 'mysql-test/r/temp_table.result'
--- a/mysql-test/r/temp_table.result 2010-06-23 11:34:40 +0000
+++ b/mysql-test/r/temp_table.result 2010-08-20 16:00:19 +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-08-20 16:00:19 +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-08-18 09:35:41 +0000
+++ b/mysql-test/t/merge.test 2010-08-20 16:00:19 +0000
@@ -2114,6 +2114,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/sp.test'
--- a/mysql-test/t/sp.test 2010-07-30 15:28:36 +0000
+++ b/mysql-test/t/sp.test 2010-08-20 16:00:19 +0000
@@ -1325,7 +1325,7 @@ lock tables v2 read, mysql.proc read|
select * from v2|
select * from v1|
# These should not work as we have too little instances of tables locked
---error ER_TABLE_NOT_LOCKED
+--error ER_VIEW_INVALID
select * from v1, t1|
--error ER_TABLE_NOT_LOCKED
select f4()|
=== 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-08-20 16:00:19 +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/lock.cc'
--- a/sql/lock.cc 2010-08-12 13:50:23 +0000
+++ b/sql/lock.cc 2010-08-20 16:00:19 +0000
@@ -77,7 +77,7 @@
#include "debug_sync.h"
#include "unireg.h" // REQUIRED: for other includes
#include "lock.h"
-#include "sql_base.h" // close_tables_for_reopen
+#include "sql_base.h"
#include "sql_parse.h" // is_log_table_write_query
#include "sql_acl.h" // SUPER_ACL
#include <hash.h>
=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc 2010-07-15 13:47:50 +0000
+++ b/sql/log_event_old.cc 2010-08-20 16:00:19 +0000
@@ -7,7 +7,7 @@
#include "log_event.h"
#ifndef MYSQL_CLIENT
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE
-#include "sql_base.h" // close_tables_for_reopen
+#include "sql_base.h"
#include "key.h" // key_copy
#include "lock.h" // mysql_unlock_tables
#include "sql_parse.h" // mysql_reset_thd_for_next_command
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc 2010-08-12 13:55:27 +0000
+++ b/sql/sp_head.cc 2010-08-20 16:00:19 +0000
@@ -2913,6 +2913,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_seq(thd, m_lex->query_tables);
+
+ if (!res && open_tables)
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
if (!res)
@@ -4129,6 +4132,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-08-18 11:29:04 +0000
+++ b/sql/sql_admin.cc 2010-08-20 16:00:19 +0000
@@ -272,8 +272,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];
@@ -385,6 +383,9 @@ static bool mysql_admin_table(THD* thd,
trans_rollback(thd);
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
DBUG_PRINT("admin", ("simple error, admin next table"));
continue;
case -1: // error, message could be written to net
@@ -460,6 +461,9 @@ static bool mysql_admin_table(THD* thd,
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
lex->reset_query_tables_list(FALSE);
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
/*
Restore Query_tables_list::sql_command value to make statement
safe for re-execution.
@@ -528,6 +532,9 @@ static bool mysql_admin_table(THD* thd,
trans_rollback(thd);
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= mysql_recreate_table(thd, table);
reenable_binlog(thd);
@@ -646,6 +653,9 @@ send_result_message:
trans_commit(thd);
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
DEBUG_SYNC(thd, "ha_admin_try_alter");
protocol->store(STRING_WITH_LEN("note"), system_charset_info);
protocol->store(STRING_WITH_LEN(
@@ -672,8 +682,11 @@ 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
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
+ if (!result_code && // recreation went ok
+ !table->table) // not a temporary table opened above
{
/* Clear the ticket released above. */
table->mdl_request.ticket= NULL;
@@ -786,6 +799,9 @@ send_result_message:
trans_commit_implicit(thd);
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
+ /* Re-open temporary tables after close_thread_tables(). */
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto err;
/*
If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
@@ -815,8 +831,7 @@ 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);
}
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2010-08-20 12:20:19 +0000
+++ b/sql/sql_base.cc 2010-08-20 16:00:19 +0000
@@ -2617,46 +2617,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 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)
{
@@ -2671,6 +2667,8 @@ bool open_table(THD *thd, TABLE_LIST *ta
my_hash_value_type hash_value;
DBUG_ENTER("open_table");
+ 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);
@@ -2707,57 +2705,6 @@ bool open_table(THD *thd, TABLE_LIST *ta
DBUG_RETURN(TRUE);
}
}
- /*
- Unless requested otherwise, try to resolve this table in the list
- of temporary tables of this thread. In MySQL temporary tables
- are always thread-local and "shadow" possible base tables with the
- same name. This block implements the behaviour.
- TODO: move this block into a separate function.
- */
- if (table_list->open_type != OT_BASE_ONLY &&
- ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
- {
- for (table= thd->temporary_tables; table ; table=table->next)
- {
- if (table->s->table_cache_key.length == key_length +
- TMP_TABLE_KEY_EXTRA &&
- !memcmp(table->s->table_cache_key.str, key,
- key_length + TMP_TABLE_KEY_EXTRA))
- {
- /*
- We're trying to use the same temporary table twice in a query.
- Right now we don't support this because a temporary table
- is always represented by only one TABLE object in THD, and
- it can not be cloned. Emit an error for an unsupported behaviour.
- */
- if (table->query_id)
- {
- DBUG_PRINT("error",
- ("query_id: %lu server_id: %u pseudo_thread_id: %lu",
- (ulong) table->query_id, (uint) thd->server_id,
- (ulong) thd->variables.pseudo_thread_id));
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- DBUG_RETURN(TRUE);
- }
- table->query_id= thd->query_id;
- thd->thread_specific_used= TRUE;
- DBUG_PRINT("info",("Using temporary table"));
- goto reset;
- }
- }
- }
-
- if (table_list->open_type == OT_TEMPORARY_ONLY ||
- (flags & MYSQL_OPEN_TEMPORARY_ONLY))
- {
- if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
- {
- my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
- DBUG_RETURN(TRUE);
- }
- else
- DBUG_RETURN(FALSE);
- }
/*
The table is not temporary - if we're in pre-locked or LOCK TABLES
@@ -2859,7 +2806,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.
@@ -4362,6 +4309,26 @@ open_and_process_table(THD *thd, LEX *le
error= TRUE;
goto end;
}
+
+ if (tables->table)
+ {
+ DBUG_ASSERT(is_temporary_table(tables->table));
+ DBUG_RETURN(FALSE);
+ }
+
+ if (tables->open_type == OT_TEMPORARY_ONLY)
+ {
+ /* We're in CREATE TEMPORARY TABLE statement. */
+
+ if (tables->open_strategy == TABLE_LIST::OPEN_NORMAL)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), tables->db, tables->table_name);
+ DBUG_RETURN(TRUE);
+ }
+
+ 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)++;
@@ -4371,6 +4338,29 @@ open_and_process_table(THD *thd, LEX *le
if (tables->prelocking_placeholder)
{
+ if (thd->locked_tables_mode)
+ {
+ /*
+ No need to pre-open new tables from the prelocking list if we are in
+ "locked tables mode" (i.e. all needed tables should be already
+ opened and locked). The table will be tried to open as usual during
+ execution.
+ */
+ DBUG_RETURN(FALSE);
+ }
+
+ if (tables->open_type != OT_BASE_ONLY)
+ {
+ /*
+ TABLE_LIST::open_type is not OT_BASE_ONLY. That means there is a
+ temporary table for that TABLE_LIST instance (there might be also a
+ base table, but that's not important because temporary tables take
+ precedence over base ones). Thus, there is no reason to pre-open
+ base table. Proper table will be opened during execution.
+ */
+ DBUG_RETURN(FALSE);
+ }
+
/*
For the tables added by the pre-locking code, attempt to open
the table but fail silently if the table does not exist.
@@ -4571,7 +4561,6 @@ lock_table_names(THD *thd,
{
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))))
@@ -4639,7 +4628,6 @@ open_tables_check_upgradable_mdl(THD *th
{
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))))
@@ -4844,6 +4832,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_seq(thd, *start))
+ goto err;
+
error= FALSE;
goto restart;
}
@@ -4890,6 +4882,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_seq(thd, *start))
+ goto err;
+
error= FALSE;
goto restart;
}
@@ -4920,6 +4916,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)
{
@@ -5744,6 +5745,129 @@ void close_tables_for_reopen(THD *thd, T
}
+/**
+ 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).
+
+ @return Error status.
+ @retval FALSE On success. If tmp_table is NULL, temporary table does
+ not exist for the specified key; if tmp_table is not
+ NULL, the temporary table was found.
+ @retval TRUE On error. my_error() has been called.
+*/
+
+bool open_temporary_table(THD *thd, TABLE_LIST *tl, TABLE **tmp_table)
+{
+ DBUG_ENTER("open_temporary_table");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
+
+ *tmp_table= NULL;
+
+ 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);
+
+ if (!table)
+ 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;
+
+ set_table_attributes_after_opening(thd, tl, table);
+
+ DBUG_PRINT("info", ("Using temporary table"));
+ *tmp_table= table;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+bool open_and_process_temporary_table_seq(THD *thd, TABLE_LIST *tl_seq)
+{
+ DBUG_ENTER("open_and_process_temporary_table_seq");
+
+ for (TABLE_LIST *tl= tl_seq; 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 (open_temporary_table(thd, tl, &tl->table))
+ DBUG_RETURN(TRUE);
+
+ if (!tl->table)
+ DBUG_RETURN(FALSE);
+
+ /* Check and update metadata version of a base table. */
+ if (check_and_update_table_version(thd, tl, tl->table->s))
+ DBUG_RETURN(TRUE);
+
+ /* Non-MERGE tables ignore this call. */
+ if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Open a single table from disk without table caching and don't set it in
open_list.
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2010-08-20 12:20:19 +0000
+++ b/sql/sql_base.h 2010-08-20 16:00:19 +0000
@@ -94,7 +94,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
/**
@@ -257,6 +257,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_seq(THD *thd, TABLE_LIST *tl_seq);
+bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl);
+bool open_temporary_table(THD *thd, TABLE_LIST *table_list, TABLE **tmp_table);
bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
/* Functions to work with system tables. */
@@ -530,6 +533,31 @@ private:
/**
+ Indicate if a TABLE instance represents a temporary table.
+*/
+
+inline bool is_temporary_table(TABLE *table)
+{
+ /*
+ NOTE: 'table->s' might be NULL when 'table' is not.
+ For instance: 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-08-18 11:29:04 +0000
+++ b/sql/sql_class.h 2010-08-20 16:00:19 +0000
@@ -1007,6 +1007,12 @@ public:
use the prelocked tables, instead of opening their own ones.
Prelocked mode is turned off automatically once close_thread_tables()
of the main statement is called.
+
+ "Locked tables mode" is ON if locked_tables_mode is not LTM_NONE.
+
+ If "Locked tables mode" is ON the server does not open/lock new tables,
+ it just looks for a table in the list of open tables. If the table is
+ not there, an error is thrown.
*/
enum enum_locked_tables_mode locked_tables_mode;
uint current_tablenr;
@@ -3498,6 +3504,19 @@ public:
*/
#define CF_CAN_GENERATE_ROW_EVENTS (1U << 11)
+/**
+ Identifies statements which may deal with temporary tables, thus
+ temporary tables should be open before executing the sql command.
+*/
+#define CF_OPEN_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_delete.cc'
--- a/sql/sql_delete.cc 2010-07-28 11:17:19 +0000
+++ b/sql/sql_delete.cc 2010-08-20 16:00:19 +0000
@@ -30,7 +30,6 @@
#include "sql_parse.h" // mysql_init_select
#include "sql_acl.h" // *_ACL
#include "filesort.h" // filesort
-#include "sql_handler.h" // mysql_ha_rm_tables
#include "sql_select.h"
#include "sp_head.h"
#include "sql_trigger.h"
=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc 2010-08-12 13:50:23 +0000
+++ b/sql/sql_handler.cc 2010-08-20 16:00:19 +0000
@@ -290,7 +290,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
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-08-18 11:55:37 +0000
+++ b/sql/sql_insert.cc 2010-08-20 16:00:19 +0000
@@ -3601,8 +3601,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, &table))
{
/*
This shouldn't happen as creation of temporary table should make
@@ -3611,8 +3610,6 @@ static TABLE *create_table_from_items(TH
*/
drop_temporary_table(thd, create_table);
}
- else
- table= create_table->table;
}
}
if (!table) // open failed
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-08-20 09:04:33 +0000
+++ b/sql/sql_parse.cc 2010-08-20 16:00:19 +0000
@@ -26,7 +26,7 @@
// start_waiting_global_read_lock,
// lock_global_read_lock,
// make_global_read_lock_block_commit
-#include "sql_base.h" // find_temporary_tablesx
+#include "sql_base.h" // find_temporary_table
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
// calc_sum_of_all_status
@@ -287,8 +287,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
- sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS;
- sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
@@ -346,7 +344,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;
@@ -419,6 +417,47 @@ 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;
+
+ // Temporary tables should be opened for the following commands:
+
+ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_TRUNCATE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_LOAD]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_DROP_INDEX]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_UPDATE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_INSERT]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_DELETE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_REPLACE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_SELECT]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_SET_OPTION]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_DO]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_CALL]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_ANALYZE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_CHECK]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_CHECKSUM]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_OPTIMIZE]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_REPAIR]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_OPEN_TMP_TABLES;
+ sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_OPEN_TMP_TABLES;
+
+ // Open handlers should be closed for the following commands:
+
+ 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_PRELOAD_KEYS]|= CF_HA_CLOSE;
+ sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_HA_CLOSE;
}
bool sqlcom_can_generate_row_events(const THD *thd)
@@ -2097,6 +2136,18 @@ mysql_execute_command(THD *thd)
DEBUG_SYNC(thd,"before_execute_sql_command");
#endif
+ if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE)
+ {
+ for (TABLE_LIST *tl= all_tables; tl; tl= tl->next_global)
+ mysql_ha_rm_tables(thd, tl);
+ }
+
+ if (sql_command_flags[lex->sql_command] & CF_OPEN_TMP_TABLES)
+ {
+ if (open_and_process_temporary_table_seq(thd, all_tables))
+ goto error;
+ }
+
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -2173,7 +2224,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;
@@ -2401,9 +2452,20 @@ case SQLCOM_PREPARE:
goto end_with_restore_list;
}
+ if (lex->create_info.merge_list.elements)
+ {
+ if (open_and_process_temporary_table_seq(
+ 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;
@@ -2455,9 +2517,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;
@@ -2615,6 +2674,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 */
/*
@@ -2759,6 +2819,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_seq(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.
@@ -3223,6 +3290,10 @@ end_with_restore_list:
thd->mdl_context.release_transactional_locks();
if (res)
goto error;
+
+ if (open_and_process_temporary_table_seq(thd, all_tables))
+ goto error;
+
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
@@ -4601,10 +4672,15 @@ bool check_single_table_access(THD *thd,
else
db_name= all_tables->db;
- if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege,
- &all_tables->grant.m_internal,
- 0, no_errors))
+ bool res= check_access(thd, privilege, db_name,
+ &all_tables->grant.privilege,
+ &all_tables->grant.m_internal,
+ 0, no_errors);
+
+ if (is_temporary_table(all_tables))
+ all_tables->table->grant= all_tables->grant;
+
+ if (res)
goto deny;
/* Show only 1 table for check_grant */
@@ -5021,16 +5097,19 @@ 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(),
- &tables->grant.privilege,
- &tables->grant.m_internal,
- 0, no_errors))
+ bool res= check_access(thd, want_access, tables->get_db_name(),
+ &tables->grant.privilege,
+ &tables->grant.m_internal,
+ 0, no_errors);
+
+ if (is_temporary_table(tables))
+ tables->table->grant= tables->grant;
+
+ if (res)
goto deny;
}
thd->security_ctx= backup_ctx;
=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc 2010-08-18 09:35:41 +0000
+++ b/sql/sql_prepare.cc 2010-08-20 16:00:19 +0000
@@ -105,6 +105,7 @@ When one supplies long data for a placeh
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
+#include "sql_handler.h" // mysql_ha_rm_tables
#include "probes_mysql.h"
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
@@ -1714,6 +1715,15 @@ static bool mysql_test_create_table(Prep
TABLE_LIST *create_table= lex->query_tables;
TABLE_LIST *tables= lex->create_last_non_select_table->next_global;
+ if (lex->create_info.merge_list.elements)
+ {
+ if (open_and_process_temporary_table_seq(
+ thd, lex->create_info.merge_list.first))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ }
+
if (create_table_precheck(thd, tables, create_table))
DBUG_RETURN(TRUE);
@@ -1777,6 +1787,12 @@ static bool mysql_test_create_view(Prepa
if (create_view_precheck(thd, tables, view, lex->create_view_mode))
goto err;
+ for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
+ {
+ if (is_temporary_table(tl))
+ tl->table->grant= tl->grant;
+ }
+
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
goto err;
@@ -1963,6 +1979,21 @@ 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)
+ {
+ for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
+ mysql_ha_rm_tables(thd, tl);
+ }
+
+ // 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_OPEN_TMP_TABLES)
+ {
+ if (open_and_process_temporary_table_seq(thd, tables))
+ goto error;
+ }
+
switch (sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
@@ -2093,6 +2124,43 @@ static bool check_prepared_statement(Pre
}
break;
}
+
+ // Open temporary tables added by prelocking.
+ if (sql_command_flags[sql_command] & CF_OPEN_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_show.cc'
--- a/sql/sql_show.cc 2010-08-18 11:29:04 +0000
+++ b/sql/sql_show.cc 2010-08-20 16:00:19 +0000
@@ -3008,11 +3008,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_seq(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");
@@ -3043,6 +3050,7 @@ fill_schema_show_cols_or_idxs(THD *thd,
thd->temporary_tables= 0;
close_tables_for_reopen(thd, &show_table_list,
open_tables_state_backup->mdl_system_tables_svp);
+ error= open_and_process_temporary_table_seq(thd, show_table_list) || error;
DBUG_RETURN(error);
}
@@ -3658,6 +3666,8 @@ int get_all_tables(THD *thd, TABLE_LIST
&tmp_lex_string);
close_tables_for_reopen(thd, &show_table_list,
open_tables_state_backup.mdl_system_tables_svp);
+ if (open_and_process_temporary_table_seq(thd, show_table_list))
+ goto err;
}
DBUG_ASSERT(!lex->query_tables_own_last);
if (res)
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2010-08-20 12:20:19 +0000
+++ b/sql/sql_table.cc 2010-08-20 16:00:19 +0000
@@ -5612,8 +5612,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. */
@@ -6229,14 +6227,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_and_process_temporary_table(thd, &tbl);
new_table= tbl.table;
}
else
@@ -6925,11 +6921,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. */
@@ -6969,13 +6960,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);
@@ -7073,11 +7067,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_seq(thd, tables))
+ goto err;
}
if (protocol->write())
goto err;
=== modified file 'sql/sql_truncate.cc'
--- a/sql/sql_truncate.cc 2010-08-20 12:20:19 +0000
+++ b/sql/sql_truncate.cc 2010-08-20 16:00:19 +0000
@@ -23,7 +23,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"
@@ -387,24 +387,26 @@ static bool open_and_lock_table_for_trun
bool mysql_truncate_table(THD *thd, TABLE_LIST *table_ref)
{
- TABLE *table;
- bool error= TRUE, binlog_stmt;
+ bool error= TRUE;
+ bool binlog_stmt= FALSE;
MDL_ticket *mdl_ticket= NULL;
DBUG_ENTER("mysql_truncate_table");
- /* Remove tables from the HANDLER's hash. */
- mysql_ha_rm_tables(thd, table_ref);
+ DBUG_ASSERT((!table_ref->table) ||
+ (table_ref->table && table_ref->table->s));
/* 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);
@@ -416,11 +418,10 @@ bool mysql_truncate_table(THD *thd, TABL
table and delete all rows. In such a manner this can in fact
open several tables if it's a temporary MyISAMMRG table.
*/
- if (open_and_lock_tables(thd, table_ref, FALSE,
- MYSQL_OPEN_TEMPORARY_ONLY))
+ if (open_and_lock_tables(thd, table_ref, FALSE, 0))
DBUG_RETURN(TRUE);
- error= delete_all_rows(thd, table_ref->table);
+ error= delete_all_rows(thd, tmp_table);
}
/*
@@ -500,7 +501,7 @@ bool Truncate_statement::execute(THD *th
bool res= TRUE;
DBUG_ENTER("Truncate_statement::execute");
- if (check_one_table_access(thd, DROP_ACL, first_table))
+ if (check_table_access(thd, DROP_ACL, first_table, FALSE, 1, FALSE))
goto error;
/*
Don't allow this within a transaction because we want to use
=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc 2010-08-09 12:11:29 +0000
+++ b/sql/sql_update.cc 2010-08-20 16:00:19 +0000
@@ -24,7 +24,7 @@
#include "unireg.h" // REQUIRED: for other includes
#include "sql_update.h"
#include "sql_cache.h" // query_cache_*
-#include "sql_base.h" // close_tables_for_reopen
+#include "sql_base.h"
#include "sql_parse.h" // cleanup_items
#include "sql_partition.h" // partition_key_modified
#include "sql_select.h"
=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc 2010-08-18 11:55:37 +0000
+++ b/sql/sql_view.cc 2010-08-20 16:00:19 +0000
@@ -442,6 +442,18 @@ bool mysql_create_view(THD *thd, TABLE_L
goto err;
}
+ for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global)
+ {
+ if (tl->table)
+ continue;
+
+ if (open_and_process_temporary_table(thd, tl))
+ {
+ res= TRUE;
+ goto err;
+ }
+ }
+
view= lex->unlink_first_table(&link_to_local);
if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))
Attachment: [text/bzr-bundle] bzr/alik@sun.com-20100820160019-pw9ii5pd7k8hcmcg.bundle
| Thread |
|---|
| • bzr commit into mysql-5.5-bugfixing branch (alik:3120) Bug#27480 | Alexander Nozdrin | 20 Aug |