mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-5535: Cannot reopen temporary table
Temporary table being created by outer statement should not be visible to inner statement. And if inner statement creates a table with same name. The whole statement should fail with ER_TABLE_EXISTS_ERROR. Implemented by temporarily de-linking the TABLE_SHARE being created by outer statement so that it remains hidden to the inner statement.
This commit is contained in:
@ -19,6 +19,28 @@ DROP TABLE t1;
|
||||
#
|
||||
# CREATE & Stored routines
|
||||
#
|
||||
CREATE FUNCTION f1() RETURNS INT
|
||||
BEGIN
|
||||
DROP TEMPORARY TABLE t1;
|
||||
RETURN 1;
|
||||
END|
|
||||
CREATE TEMPORARY TABLE t1 AS SELECT f1();
|
||||
ERROR 42S02: Unknown table 'temp_db.t1'
|
||||
DROP FUNCTION f1;
|
||||
CREATE FUNCTION f2() RETURNS INT
|
||||
BEGIN
|
||||
CREATE TEMPORARY TABLE t2(i INT);
|
||||
INSERT INTO t2 VALUES(1), (2);
|
||||
RETURN 1;
|
||||
END|
|
||||
CREATE TEMPORARY TABLE t2 AS SELECT f2();
|
||||
ERROR 42S01: Table 't2' already exists
|
||||
SELECT * FROM t2;
|
||||
i
|
||||
1
|
||||
2
|
||||
DROP TABLE t2;
|
||||
DROP FUNCTION f2;
|
||||
CREATE TEMPORARY TABLE t3 AS SELECT 1 AS a;
|
||||
CREATE PROCEDURE p1()
|
||||
BEGIN
|
||||
|
@ -1524,14 +1524,14 @@ drop temporary table t1;
|
||||
return 1;
|
||||
end|
|
||||
create temporary table t1 as select f1();
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
ERROR 42S02: Unknown table 'test.t1'
|
||||
create function f2() returns int
|
||||
begin
|
||||
create temporary table t2 as select f1();
|
||||
return 1;
|
||||
end|
|
||||
create temporary table t1 as select f2();
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
ERROR 42S02: Unknown table 'test.t1'
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
create function f1() returns int
|
||||
@ -1545,7 +1545,7 @@ create temporary table t2 as select f1();
|
||||
return 1;
|
||||
end|
|
||||
create temporary table t1 as select f2();
|
||||
ERROR HY000: Can't reopen table: 't2'
|
||||
ERROR 42S02: Unknown table 'test.t2,test.t1'
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
create temporary table t2(a int);
|
||||
|
@ -24,6 +24,31 @@ DROP TABLE t1;
|
||||
--echo # CREATE & Stored routines
|
||||
--echo #
|
||||
|
||||
DELIMITER |;
|
||||
CREATE FUNCTION f1() RETURNS INT
|
||||
BEGIN
|
||||
DROP TEMPORARY TABLE t1;
|
||||
RETURN 1;
|
||||
END|
|
||||
DELIMITER ;|
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
CREATE TEMPORARY TABLE t1 AS SELECT f1();
|
||||
DROP FUNCTION f1;
|
||||
|
||||
DELIMITER |;
|
||||
CREATE FUNCTION f2() RETURNS INT
|
||||
BEGIN
|
||||
CREATE TEMPORARY TABLE t2(i INT);
|
||||
INSERT INTO t2 VALUES(1), (2);
|
||||
RETURN 1;
|
||||
END|
|
||||
DELIMITER ;|
|
||||
--error ER_TABLE_EXISTS_ERROR
|
||||
CREATE TEMPORARY TABLE t2 AS SELECT f2();
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t2;
|
||||
DROP FUNCTION f2;
|
||||
|
||||
CREATE TEMPORARY TABLE t3 AS SELECT 1 AS a;
|
||||
DELIMITER |;
|
||||
CREATE PROCEDURE p1()
|
||||
|
@ -2231,7 +2231,7 @@ begin
|
||||
return 1;
|
||||
end|
|
||||
delimiter ;|
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
create temporary table t1 as select f1();
|
||||
|
||||
delimiter |;
|
||||
@ -2241,7 +2241,7 @@ begin
|
||||
return 1;
|
||||
end|
|
||||
delimiter ;|
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
create temporary table t1 as select f2();
|
||||
|
||||
drop function f1;
|
||||
@ -2259,7 +2259,7 @@ begin
|
||||
return 1;
|
||||
end|
|
||||
delimiter ;|
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
create temporary table t1 as select f2();
|
||||
|
||||
drop function f1;
|
||||
|
@ -4066,6 +4066,9 @@ public:
|
||||
void mark_tmp_tables_as_free_for_reuse();
|
||||
void mark_tmp_table_as_free_for_reuse(TABLE *table);
|
||||
|
||||
TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table);
|
||||
void restore_tmp_table_share(TMP_TABLE_SHARE *share);
|
||||
|
||||
private:
|
||||
/* Whether a lock has been acquired? */
|
||||
bool m_tmp_tables_locked;
|
||||
@ -4617,6 +4620,7 @@ class select_create: public select_insert {
|
||||
/* m_lock or thd->extra_lock */
|
||||
MYSQL_LOCK **m_plock;
|
||||
bool exit_done;
|
||||
TMP_TABLE_SHARE *saved_tmp_table_share;
|
||||
|
||||
public:
|
||||
select_create(THD *thd_arg, TABLE_LIST *table_arg,
|
||||
@ -4629,7 +4633,8 @@ public:
|
||||
create_info(create_info_par),
|
||||
select_tables(select_tables_arg),
|
||||
alter_info(alter_info_arg),
|
||||
m_plock(NULL), exit_done(0)
|
||||
m_plock(NULL), exit_done(0),
|
||||
saved_tmp_table_share(0)
|
||||
{}
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
|
||||
|
@ -4226,6 +4226,18 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
/* abort() deletes table */
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (create_info->tmp_table())
|
||||
{
|
||||
/*
|
||||
When the temporary table was created & opened in create_table_impl(),
|
||||
the table's TABLE_SHARE (and thus TABLE) object was also linked to THD
|
||||
temporary tables lists. So, we must temporarily remove it from the
|
||||
list to keep them inaccessible from inner statements.
|
||||
e.g. CREATE TEMPORARY TABLE `t1` AS SELECT * FROM `t1`;
|
||||
*/
|
||||
saved_tmp_table_share= thd->save_tmp_table_share(create_table->table);
|
||||
}
|
||||
|
||||
if (extra_lock)
|
||||
{
|
||||
DBUG_ASSERT(m_plock == NULL);
|
||||
@ -4341,6 +4353,27 @@ bool select_create::send_eof()
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
|
||||
if (table->s->tmp_table)
|
||||
{
|
||||
/*
|
||||
Now is good time to add the new table to THD temporary tables list.
|
||||
But, before that we need to check if same table got created by the sub-
|
||||
statement.
|
||||
*/
|
||||
if (thd->find_tmp_table_share(table->s->table_cache_key.str,
|
||||
table->s->table_cache_key.length))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table->alias.c_ptr());
|
||||
abort_result_set();
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(saved_tmp_table_share);
|
||||
thd->restore_tmp_table_share(saved_tmp_table_share);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Do an implicit commit at end of statement for non-temporary
|
||||
tables. This can fail, but we should unlock the table
|
||||
@ -4466,6 +4499,12 @@ void select_create::abort_result_set()
|
||||
{
|
||||
bool tmp_table= table->s->tmp_table;
|
||||
|
||||
if (tmp_table)
|
||||
{
|
||||
DBUG_ASSERT(saved_tmp_table_share);
|
||||
thd->restore_tmp_table_share(saved_tmp_table_share);
|
||||
}
|
||||
|
||||
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
||||
table->auto_increment_field_not_null= FALSE;
|
||||
|
@ -801,6 +801,50 @@ void THD::mark_tmp_table_as_free_for_reuse(TABLE *table)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove and return the specified table's TABLE_SHARE from the temporary
|
||||
tables list.
|
||||
|
||||
@param table [IN] Table
|
||||
|
||||
@return TMP_TABLE_SHARE of the specified table.
|
||||
*/
|
||||
TMP_TABLE_SHARE *THD::save_tmp_table_share(TABLE *table)
|
||||
{
|
||||
DBUG_ENTER("THD::save_tmp_table_share");
|
||||
|
||||
TMP_TABLE_SHARE *share;
|
||||
|
||||
lock_temporary_tables();
|
||||
DBUG_ASSERT(temporary_tables);
|
||||
share= tmp_table_share(table);
|
||||
temporary_tables->remove(share);
|
||||
unlock_temporary_tables();
|
||||
|
||||
DBUG_RETURN(share);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add the specified TMP_TABLE_SHARE to the temporary tables list.
|
||||
|
||||
@param share [IN] Table share
|
||||
|
||||
@return void
|
||||
*/
|
||||
void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share)
|
||||
{
|
||||
DBUG_ENTER("THD::restore_tmp_table_share");
|
||||
|
||||
lock_temporary_tables();
|
||||
DBUG_ASSERT(temporary_tables);
|
||||
temporary_tables->push_front(share);
|
||||
unlock_temporary_tables();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
If its a replication slave, report whether slave temporary tables
|
||||
exist (Relay_log_info::save_temporary_tables) or report about THD
|
||||
|
Reference in New Issue
Block a user