#At file:///mnt/raid/alik/MySQL/bzr/00/bug27480/mysql-trunk-bf-bug27480/ based on revid:alik@stripped
3092 Alexander Nozdrin 2010-06-03
Preliminary patch for Bug#27480 (Extend CREATE TEMPORARY TABLES
privilege to allow temp table operations). All tests pass.
added:
mysql-test/r/create_notembedded.result
mysql-test/t/create_notembedded.test
modified:
sql/lock.h
sql/sql_acl.cc
sql/sql_base.cc
sql/sql_base.h
sql/sql_class.h
sql/sql_insert.cc
sql/sql_parse.cc
=== added file 'mysql-test/r/create_notembedded.result'
--- a/mysql-test/r/create_notembedded.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/create_notembedded.result 2010-06-03 09:01:18 +0000
@@ -0,0 +1,102 @@
+DROP DATABASE IF EXISTS mysqltest2;
+CREATE DATABASE mysqltest2;
+GRANT CREATE, SELECT ON test.* TO mysqltest_u1@localhost;
+GRANT CREATE TEMPORARY TABLES ON mysqltest2.* TO mysqltest_u1@localhost;
+CREATE TEMPORARY TABLE tmp1(a INT);
+CREATE TEMPORARY TABLE tmp2(a INT);
+CREATE TABLE t1(a INT);
+ERROR 42000: CREATE command denied to user 'mysqltest_u1'@'localhost' for table 't1'
+CREATE TABLE test.t1(a INT);
+INSERT INTO tmp1 VALUES (11), (12), (13);
+INSERT INTO tmp2 VALUES (21), (22), (23);
+CREATE TEMPORARY TABLE tmp3(b INT);
+INSERT INTO tmp3 SELECT a FROM tmp1 UNION SELECT a FROM tmp2;
+SELECT * FROM tmp3;
+b
+11
+12
+13
+21
+22
+23
+SELECT * FROM tmp1;
+a
+11
+12
+13
+SELECT * FROM tmp1, tmp2;
+a a
+11 21
+12 21
+13 21
+11 22
+12 22
+13 22
+11 23
+12 23
+13 23
+SELECT * FROM tmp1, t1, tmp2;
+ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
+SELECT * FROM tmp1, test.t1, tmp2;
+a a a
+UPDATE tmp1 SET a = a * 10;
+SELECT * FROM tmp1;
+a
+110
+120
+130
+UPDATE tmp2 SET a = a - 20 WHERE a >= 10;
+SELECT * FROM tmp2;
+a
+1
+2
+3
+UPDATE tmp1, tmp3
+SET a = a * 1, b = b * 1
+WHERE b < 100;
+SELECT * FROM tmp1;
+a
+110
+120
+130
+SELECT * FROM tmp3;
+b
+11
+12
+13
+21
+22
+23
+DELETE FROM tmp1;
+SELECT * FROM tmp1;
+a
+DELETE FROM tmp2 WHERE a > 2;
+SELECT * FROM tmp2;
+a
+1
+2
+DELETE FROM tmp2;
+INSERT INTO tmp1 VALUES (1), (2), (3);
+INSERT INTO tmp2 VALUES (2), (3), (4);
+SELECT * FROM tmp1;
+a
+1
+2
+3
+SELECT * FROM tmp2;
+a
+2
+3
+4
+DELETE a1, a2
+FROM tmp1 AS a1 INNER JOIN tmp2 AS a2
+WHERE a1.a = a2.a;
+SELECT * FROM tmp1;
+a
+1
+SELECT * FROM tmp2;
+a
+4
+DROP DATABASE mysqltest2;
+DROP TABLE t1;
+DROP USER mysqltest_u1@localhost;
=== added file 'mysql-test/t/create_notembedded.test'
--- a/mysql-test/t/create_notembedded.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/create_notembedded.test 2010-06-03 09:01:18 +0000
@@ -0,0 +1,92 @@
+# Grant tests not performed with embedded server
+-- source include/not_embedded.inc
+
+#
+# Bug#27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table
+# operations.
+#
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest2;
+--enable_warnings
+
+CREATE DATABASE mysqltest2;
+
+GRANT CREATE, SELECT ON test.* TO mysqltest_u1@localhost;
+GRANT CREATE TEMPORARY TABLES ON mysqltest2.* TO mysqltest_u1@localhost;
+
+--connect (con1, localhost, mysqltest_u1, , mysqltest2)
+
+CREATE TEMPORARY TABLE tmp1(a INT);
+CREATE TEMPORARY TABLE tmp2(a INT);
+
+--error ER_TABLEACCESS_DENIED_ERROR
+CREATE TABLE t1(a INT);
+
+CREATE TABLE test.t1(a INT);
+
+# Check INSERT INTO.
+
+INSERT INTO tmp1 VALUES (11), (12), (13);
+INSERT INTO tmp2 VALUES (21), (22), (23);
+
+CREATE TEMPORARY TABLE tmp3(b INT);
+INSERT INTO tmp3 SELECT a FROM tmp1 UNION SELECT a FROM tmp2;
+SELECT * FROM tmp3;
+
+# Check SELECT.
+
+SELECT * FROM tmp1;
+
+SELECT * FROM tmp1, tmp2;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM tmp1, t1, tmp2;
+
+SELECT * FROM tmp1, test.t1, tmp2;
+
+# Check UPDATE.
+
+UPDATE tmp1 SET a = a * 10;
+SELECT * FROM tmp1;
+
+UPDATE tmp2 SET a = a - 20 WHERE a >= 10;
+SELECT * FROM tmp2;
+
+UPDATE tmp1, tmp3
+SET a = a * 1, b = b * 1
+WHERE b < 100;
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp3;
+
+# Check DELETE.
+
+DELETE FROM tmp1;
+SELECT * FROM tmp1;
+
+DELETE FROM tmp2 WHERE a > 2;
+SELECT * FROM tmp2;
+
+DELETE FROM tmp2;
+
+INSERT INTO tmp1 VALUES (1), (2), (3);
+INSERT INTO tmp2 VALUES (2), (3), (4);
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp2;
+
+DELETE a1, a2
+FROM tmp1 AS a1 INNER JOIN tmp2 AS a2
+WHERE a1.a = a2.a;
+
+SELECT * FROM tmp1;
+SELECT * FROM tmp2;
+
+--connection default
+--disconnect con1
+
+DROP DATABASE mysqltest2;
+DROP TABLE t1;
+
+DROP USER mysqltest_u1@localhost;
=== modified file 'sql/lock.h'
--- a/sql/lock.h 2010-05-28 22:13:31 +0000
+++ b/sql/lock.h 2010-06-03 09:01:18 +0000
@@ -12,7 +12,7 @@ typedef struct st_mysql_lock MYSQL_LOCK;
/* 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
#define MYSQL_OPEN_TAKE_UPGRADABLE_MDL 0x0020
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2010-05-28 05:47:58 +0000
+++ b/sql/sql_acl.cc 2010-06-03 09:01:18 +0000
@@ -3988,6 +3988,19 @@ end:
DBUG_RETURN(return_val);
}
+static bool check_grant_for_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+ TABLE *table= tl->table;
+
+ if (!table && tl->correspondent_table)
+ table= tl->correspondent_table->table;
+
+ return
+ !(table && table->s &&
+ table->s->tmp_table != NO_TMP_TABLE &&
+ !check_access(thd, CREATE_TMP_ACL, table->s->db.str, NULL, NULL, 0, TRUE));
+}
+
/**
@brief Check table level grants
@@ -4117,9 +4130,24 @@ bool check_grant(THD *thd, ulong want_ac
}
continue;
}
- if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
- table->get_db_name(), sctx->priv_user,
- table->get_table_name(), FALSE)))
+
+ grant_table= table_hash_search(sctx->host, sctx->ip,
+ table->get_db_name(), sctx->priv_user,
+ table->get_table_name(), FALSE);
+
+ if (grant_table)
+ {
+ table->grant.grant_table=grant_table; // Remember for column test
+ table->grant.version=grant_version;
+ table->grant.privilege|= grant_table->privs;
+ table->grant.want_privilege= ((want_access & COL_ACLS)
+ & ~table->grant.privilege);
+ }
+
+ if (!check_grant_for_temporary_table(thd, table))
+ continue;
+
+ if (!grant_table)
{
want_access &= ~table->grant.privilege;
goto err; // No grants
@@ -4132,12 +4160,6 @@ bool check_grant(THD *thd, ulong want_ac
if (any_combination_will_do)
continue;
- table->grant.grant_table=grant_table; // Remember for column test
- table->grant.version=grant_version;
- table->grant.privilege|= grant_table->privs;
- table->grant.want_privilege= ((want_access & COL_ACLS)
- & ~table->grant.privilege);
-
if (!(~table->grant.privilege & want_access))
continue;
@@ -4294,6 +4316,9 @@ bool check_column_grant_in_table_ref(THD
table_name= table->s->table_name.str;
}
+ if (!check_grant_for_temporary_table(thd, table_ref))
+ return FALSE;
+
if (grant->want_privilege)
return check_grant_column(thd, grant, db_name, table_name, name,
length, sctx);
@@ -4340,6 +4365,11 @@ bool check_grant_all_columns(THD *thd, u
for (; !fields->end_of_fields(); fields->next())
{
const char *field_name= fields->name();
+ bool is_tmp_table= FALSE;
+ Field *field= fields->field();
+
+ if (field && field->table && field->table->s)
+ is_tmp_table= field->table->s->tmp_table != NO_TMP_TABLE;
if (table_name != fields->get_table_name())
{
@@ -4361,19 +4391,27 @@ bool check_grant_all_columns(THD *thd, u
}
grant_table= grant->grant_table;
- DBUG_ASSERT (grant_table);
+ DBUG_ASSERT(grant_table || !grant_table && is_tmp_table);
}
}
if (want_access)
{
- GRANT_COLUMN *grant_column=
- column_hash_search(grant_table, field_name,
- (uint) strlen(field_name));
- if (grant_column)
- using_column_privileges= TRUE;
- if (!grant_column || (~grant_column->rights & want_access))
- goto err;
+ if (is_tmp_table)
+ {
+ if (check_access(thd, CREATE_TMP_ACL, db_name, NULL, NULL, 0, TRUE))
+ goto err;
+ }
+ else
+ {
+ GRANT_COLUMN *grant_column=
+ column_hash_search(grant_table, field_name,
+ (uint) strlen(field_name));
+ if (grant_column)
+ using_column_privileges= TRUE;
+ if (!grant_column || (~grant_column->rights & want_access))
+ goto err;
+ }
}
}
mysql_rwlock_unlock(&LOCK_grant);
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2010-06-01 13:49:31 +0000
+++ b/sql/sql_base.cc 2010-06-03 09:01:18 +0000
@@ -56,7 +56,6 @@
#include <io.h>
#endif
-
/**
This internal handler is used to trap internally
errors that can occur when executing open table
@@ -1975,9 +1974,12 @@ TABLE *find_temporary_table(THD *thd, co
{
TABLE_LIST table_list;
+ DBUG_ENTER("find_temporary_table(db_name, table_name)");
+
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
- return find_temporary_table(thd, &table_list);
+
+ DBUG_RETURN(find_temporary_table(thd, &table_list));
}
@@ -1985,16 +1987,26 @@ TABLE *find_temporary_table(THD *thd, TA
{
char key[MAX_DBKEY_LENGTH];
uint key_length;
- TABLE *table;
- DBUG_ENTER("find_temporary_table");
+
+ DBUG_ENTER("find_temporary_table(TABLE_LIST)");
DBUG_PRINT("enter", ("table: '%s'.'%s'",
table_list->db, table_list->table_name));
key_length= create_table_def_key(thd, key, table_list, 1);
- for (table=thd->temporary_tables ; table ; table= table->next)
+ DBUG_RETURN(find_temporary_table(thd, key, key_length));
+}
+
+
+TABLE *find_temporary_table(THD *thd,
+ const char *table_key,
+ uint table_key_length)
+{
+
+ DBUG_ENTER("find_temporary_table(table_key)");
+ for (TABLE *table= thd->temporary_tables; table; table= table->next)
{
- if (table->s->table_cache_key.length == key_length &&
- !memcmp(table->s->table_cache_key.str, key, key_length))
+ if (table->s->table_cache_key.length == table_key_length &&
+ !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
{
DBUG_PRINT("info",
("Found table. server_id: %u pseudo_thread_id: %lu",
@@ -2003,7 +2015,7 @@ TABLE *find_temporary_table(THD *thd, TA
DBUG_RETURN(table);
}
}
- DBUG_RETURN(0); // Not a temporary table
+ DBUG_RETURN(NULL); // Not a temporary table
}
@@ -2057,6 +2069,7 @@ int drop_temporary_table(THD *thd, TABLE
*/
mysql_lock_remove(thd, thd->lock, table);
close_temporary_table(thd, table, 1, 1);
+ table_list->table= NULL;
DBUG_RETURN(0);
}
@@ -2158,6 +2171,48 @@ bool rename_temporary_table(THD* thd, TA
}
+static void update_table_flags(THD *thd, TABLE_LIST *table_list, TABLE *table)
+{
+ DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
+
+ if (thd->lex->need_correct_ident())
+ table->alias_name_used= my_strcasecmp(table_alias_charset,
+ table->s->table_name.str,
+ table_list->alias);
+ /* Fix alias if table name changes */
+ if (strcmp(table->alias, table_list->alias))
+ {
+ uint length=(uint) strlen(table_list->alias)+1;
+ table->alias= (char*) my_realloc((char*) table->alias, length,
+ MYF(MY_WME));
+ memcpy((char*) table->alias, table_list->alias, length);
+ }
+ table->tablenr=thd->current_tablenr++;
+ table->used_fields=0;
+ table->const_table=0;
+ table->null_row= table->maybe_null= 0;
+ table->force_index= table->force_index_order= table->force_index_group= 0;
+ table->status=STATUS_NO_RECORD;
+ table->insert_values= 0;
+ table->fulltext_searched= 0;
+ table->file->ft_handler= 0;
+ table->reginfo.impossible_range= 0;
+ /* Catch wrong handling of the auto_increment_field_not_null. */
+ DBUG_ASSERT(!table->auto_increment_field_not_null);
+ table->auto_increment_field_not_null= FALSE;
+ if (table->timestamp_field)
+ table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
+ table->pos_in_table_list= table_list;
+ table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
+ table->clear_column_bitmaps();
+ table_list->table= table;
+ DBUG_ASSERT(table->key_read == 0);
+ /* Tables may be reused in a sub statement. */
+ if (table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN))
+ table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+}
+
+
/**
Force all other threads to stop using the table by upgrading
metadata lock on it and remove unused TABLE instances from cache.
@@ -2460,8 +2515,6 @@ open_table_get_mdl_lock(THD *thd, TABLE_
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.
@@ -2492,7 +2545,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
Open_table_context *ot_ctx, uint flags)
{
- reg1 TABLE *table;
+ TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
@@ -2538,48 +2591,14 @@ 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 (open_temporary_table(thd, table_list, &table, flags))
+ DBUG_RETURN(TRUE);
+
+ if (table)
+ goto reset;
+
+ if (table_list->open_type == OT_TEMPORARY_ONLY)
{
if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
{
@@ -2965,42 +2984,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
table->reginfo.lock_type=TL_READ; /* Assume read */
reset:
- DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE);
-
- if (thd->lex->need_correct_ident())
- table->alias_name_used= my_strcasecmp(table_alias_charset,
- table->s->table_name.str, alias);
- /* Fix alias if table name changes */
- if (strcmp(table->alias, alias))
- {
- uint length=(uint) strlen(alias)+1;
- table->alias= (char*) my_realloc((char*) table->alias, length,
- MYF(MY_WME));
- memcpy((char*) table->alias, alias, length);
- }
- table->tablenr=thd->current_tablenr++;
- table->used_fields=0;
- table->const_table=0;
- table->null_row= table->maybe_null= 0;
- table->force_index= table->force_index_order= table->force_index_group= 0;
- table->status=STATUS_NO_RECORD;
- table->insert_values= 0;
- table->fulltext_searched= 0;
- table->file->ft_handler= 0;
- table->reginfo.impossible_range= 0;
- /* Catch wrong handling of the auto_increment_field_not_null. */
- DBUG_ASSERT(!table->auto_increment_field_not_null);
- table->auto_increment_field_not_null= FALSE;
- if (table->timestamp_field)
- table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
- table->pos_in_table_list= table_list;
- table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
- table->clear_column_bitmaps();
- table_list->table= table;
- DBUG_ASSERT(table->key_read == 0);
- /* Tables may be reused in a sub statement. */
- if (table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN))
- table->file->extra(HA_EXTRA_DETACH_CHILDREN);
+ update_table_flags(thd, table_list, table);
DBUG_RETURN(FALSE);
err_unlock:
@@ -4198,6 +4182,21 @@ open_and_process_table(THD *thd, LEX *le
bool safe_to_ignore_table= FALSE;
DBUG_ENTER("open_and_process_table");
+ if ((tables->open_type == OT_BASE_ONLY ||
+ (flags & MYSQL_OPEN_SKIP_TEMPORARY)) &&
+ tables->table && tables->table->s->tmp_table != NO_TMP_TABLE)
+ {
+ tables->table->query_id= 0;
+ tables->table= NULL;
+ // XXX: what to do with THD::thread_specific_used?
+ }
+
+ if (tables->table &&
+ tables->table->s->tmp_table != NO_TMP_TABLE)
+ {
+ goto end;
+ }
+
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
@@ -4386,6 +4385,8 @@ open_and_process_table(THD *thd, LEX *le
/* MERGE tables need to access parent and child TABLE_LISTs. */
DBUG_ASSERT(tables->table->pos_in_table_list == tables);
/* Non-MERGE tables ignore this call. */
+ DBUG_PRINT("info", ("calling HA_EXTRA_ADD_CHILDREN_LIST (%s)...",
+ (char *) tables->table_name));
if (tables->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
{
error= TRUE;
@@ -4631,8 +4632,7 @@ restart:
these two flags. At this point, that does not matter as they
are not used together with MYSQL_OPEN_TAKE_UPGRADABLE_MDL.
*/
- DBUG_ASSERT(!(flags & (MYSQL_OPEN_SKIP_TEMPORARY |
- MYSQL_OPEN_TEMPORARY_ONLY)));
+ DBUG_ASSERT(!(flags & MYSQL_OPEN_SKIP_TEMPORARY));
if (thd->locked_tables_mode)
{
/*
@@ -5569,7 +5569,120 @@ void close_tables_for_reopen(THD *thd, T
/*
- Open a single table without table caching and don't set it in open_list
+ 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.
+
+ @return FALSE if success, TRUE - otherwise.
+ @retval FALSE 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.
+
+*/
+static bool open_temporary_table(THD *thd,
+ const char *table_key,
+ uint table_key_length,
+ TABLE_LIST *table_list,
+ TABLE **tmp_table,
+ uint flags)
+{
+ DBUG_ENTER("open_temporary_table");
+ DBUG_PRINT("enter", ("table: '%s'.'%s'",
+ table_list->db, table_list->table_name));
+
+ *tmp_table= NULL;
+
+ if (table_list->open_type == OT_BASE_ONLY ||
+ (flags & MYSQL_OPEN_SKIP_TEMPORARY))
+ {
+ DBUG_PRINT("info", ("skip_temporary is set"));
+ DBUG_RETURN(FALSE);
+ }
+
+ 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;
+
+ update_table_flags(thd, table_list, table);
+
+ DBUG_PRINT("info", ("Using temporary table"));
+ *tmp_table= table;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+bool open_temporary_table(THD *thd, TABLE_LIST *tl, TABLE **tmp_table,
+ uint flags)
+{
+ /*
+ If TABLE_LIST::schema_table is set, TABLE_LIST::table_name may be
+ corrupted.
+
+ TABLE_LIST::db may be an empty string, and TABLE_LIST::table_name
+ is corrupted in this case.
+ */
+
+ if (tl->schema_table || !tl->db[0])
+ return FALSE;
+
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+
+ key_length= create_table_def_key(thd, key, tl, 1);
+
+ return open_temporary_table(thd, key, key_length, tl, tmp_table, flags);
+}
+
+
+bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl)
+{
+ DBUG_ENTER("open_and_process_temporary_table");
+
+ if (open_temporary_table(thd, tl, &tl->table, 0))
+ DBUG_RETURN(TRUE);
+
+ if (!tl->table)
+ DBUG_RETURN(FALSE);
+
+ /* Non-MERGE tables ignore this call. */
+ if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
+ DBUG_RETURN(TRUE);
+
+ /* Check and update metadata version of a base table. */
+ if (check_and_update_table_version(thd, tl, tl->table->s))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Load a single temporary table from the disk without table caching and
+ don't set it in open_list.
SYNPOSIS
open_temporary_table()
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2010-05-28 05:47:58 +0000
+++ b/sql/sql_base.h 2010-06-03 09:01:18 +0000
@@ -132,8 +132,13 @@ TABLE_LIST *find_table_in_list(TABLE_LIS
TABLE_LIST *TABLE_LIST::*link,
const char *db_name,
const char *table_name);
+
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
+TABLE *find_temporary_table(THD *thd,
+ const char *table_key,
+ uint table_key_length);
+
void close_thread_tables(THD *thd);
bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
List<Item> &values,
@@ -231,6 +236,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(THD *thd, TABLE_LIST *tl);
+bool open_temporary_table(THD *thd, TABLE_LIST *table_list,
+ TABLE **tmp_table, uint flags);
void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
void remove_db_from_cache(const char *db);
void flush_tables();
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2010-06-01 23:25:08 +0000
+++ b/sql/sql_class.h 2010-06-03 09:01:18 +0000
@@ -3625,6 +3625,12 @@ 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)
+
/* Bits in server_command_flags */
/**
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2010-05-20 12:35:28 +0000
+++ b/sql/sql_insert.cc 2010-06-03 09:01:18 +0000
@@ -3628,8 +3628,7 @@ static TABLE *create_table_from_items(TH
else
{
Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT);
- if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused,
- MYSQL_OPEN_TEMPORARY_ONLY))
+ if (open_temporary_table(thd, create_table, &table, 0))
{
/*
This shouldn't happen as creation of temporary table should make
@@ -3639,7 +3638,9 @@ static TABLE *create_table_from_items(TH
drop_temporary_table(thd, create_table);
}
else
- table= create_table->table;
+ {
+ create_table->table= table;
+ }
}
}
if (!table) // open failed
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-06-01 23:25:08 +0000
+++ b/sql/sql_parse.cc 2010-06-03 09:01:18 +0000
@@ -259,10 +259,11 @@ void init_update_queries(void)
*/
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS | CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
- CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL;
+ CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
@@ -288,31 +289,41 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_PROTECT_AGAINST_GRL |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS;
+ CF_CAN_GENERATE_ROW_EVENTS |
+ CF_OPEN_TMP_TABLES;
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
@@ -342,7 +353,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 | CF_OPEN_TMP_TABLES;
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;
@@ -412,6 +423,8 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS;
+
+ sql_command_flags[SQLCOM_LOCK_TABLES]= CF_OPEN_TMP_TABLES;
}
bool sqlcom_can_generate_row_events(const THD *thd)
@@ -2228,6 +2241,15 @@ mysql_execute_command(THD *thd)
DEBUG_SYNC(thd,"before_execute_sql_command");
#endif
+ if (sql_command_flags[lex->sql_command] & CF_OPEN_TMP_TABLES)
+ {
+ for (TABLE_LIST *tl= all_tables; tl; tl= tl->next_global)
+ {
+ if (open_and_process_temporary_table(thd, tl))
+ goto error;
+ }
+ }
+
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -2304,7 +2326,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;
Attachment: [text/bzr-bundle] bzr/alik@sun.com-20100603090118-u0fn8rh0n7ez33me.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-bugfixing branch (alik:3092) Bug#27480 | Alexander Nozdrin | 3 Jun |