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 & 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 TEMPORARY TABLE t3 AS SELECT 1 AS a;
|
||||||
CREATE PROCEDURE p1()
|
CREATE PROCEDURE p1()
|
||||||
BEGIN
|
BEGIN
|
||||||
|
@ -1524,14 +1524,14 @@ drop temporary table t1;
|
|||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
create temporary table t1 as select f1();
|
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
|
create function f2() returns int
|
||||||
begin
|
begin
|
||||||
create temporary table t2 as select f1();
|
create temporary table t2 as select f1();
|
||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
create temporary table t1 as select f2();
|
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 f1;
|
||||||
drop function f2;
|
drop function f2;
|
||||||
create function f1() returns int
|
create function f1() returns int
|
||||||
@ -1545,7 +1545,7 @@ create temporary table t2 as select f1();
|
|||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
create temporary table t1 as select f2();
|
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 f1;
|
||||||
drop function f2;
|
drop function f2;
|
||||||
create temporary table t2(a int);
|
create temporary table t2(a int);
|
||||||
|
@ -24,6 +24,31 @@ DROP TABLE t1;
|
|||||||
--echo # CREATE & Stored routines
|
--echo # CREATE & Stored routines
|
||||||
--echo #
|
--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;
|
CREATE TEMPORARY TABLE t3 AS SELECT 1 AS a;
|
||||||
DELIMITER |;
|
DELIMITER |;
|
||||||
CREATE PROCEDURE p1()
|
CREATE PROCEDURE p1()
|
||||||
|
@ -2231,7 +2231,7 @@ begin
|
|||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
--error ER_CANT_REOPEN_TABLE
|
--error ER_BAD_TABLE_ERROR
|
||||||
create temporary table t1 as select f1();
|
create temporary table t1 as select f1();
|
||||||
|
|
||||||
delimiter |;
|
delimiter |;
|
||||||
@ -2241,7 +2241,7 @@ begin
|
|||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
--error ER_CANT_REOPEN_TABLE
|
--error ER_BAD_TABLE_ERROR
|
||||||
create temporary table t1 as select f2();
|
create temporary table t1 as select f2();
|
||||||
|
|
||||||
drop function f1;
|
drop function f1;
|
||||||
@ -2259,7 +2259,7 @@ begin
|
|||||||
return 1;
|
return 1;
|
||||||
end|
|
end|
|
||||||
delimiter ;|
|
delimiter ;|
|
||||||
--error ER_CANT_REOPEN_TABLE
|
--error ER_BAD_TABLE_ERROR
|
||||||
create temporary table t1 as select f2();
|
create temporary table t1 as select f2();
|
||||||
|
|
||||||
drop function f1;
|
drop function f1;
|
||||||
|
@ -4066,6 +4066,9 @@ public:
|
|||||||
void mark_tmp_tables_as_free_for_reuse();
|
void mark_tmp_tables_as_free_for_reuse();
|
||||||
void mark_tmp_table_as_free_for_reuse(TABLE *table);
|
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:
|
private:
|
||||||
/* Whether a lock has been acquired? */
|
/* Whether a lock has been acquired? */
|
||||||
bool m_tmp_tables_locked;
|
bool m_tmp_tables_locked;
|
||||||
@ -4617,6 +4620,7 @@ class select_create: public select_insert {
|
|||||||
/* m_lock or thd->extra_lock */
|
/* m_lock or thd->extra_lock */
|
||||||
MYSQL_LOCK **m_plock;
|
MYSQL_LOCK **m_plock;
|
||||||
bool exit_done;
|
bool exit_done;
|
||||||
|
TMP_TABLE_SHARE *saved_tmp_table_share;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
select_create(THD *thd_arg, TABLE_LIST *table_arg,
|
select_create(THD *thd_arg, TABLE_LIST *table_arg,
|
||||||
@ -4629,7 +4633,8 @@ public:
|
|||||||
create_info(create_info_par),
|
create_info(create_info_par),
|
||||||
select_tables(select_tables_arg),
|
select_tables(select_tables_arg),
|
||||||
alter_info(alter_info_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);
|
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 */
|
/* abort() deletes table */
|
||||||
DBUG_RETURN(-1);
|
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)
|
if (extra_lock)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(m_plock == NULL);
|
DBUG_ASSERT(m_plock == NULL);
|
||||||
@ -4341,6 +4353,27 @@ bool select_create::send_eof()
|
|||||||
DBUG_RETURN(true);
|
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
|
Do an implicit commit at end of statement for non-temporary
|
||||||
tables. This can fail, but we should unlock the table
|
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;
|
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_NO_IGNORE_DUP_KEY);
|
||||||
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
||||||
table->auto_increment_field_not_null= FALSE;
|
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
|
If its a replication slave, report whether slave temporary tables
|
||||||
exist (Relay_log_info::save_temporary_tables) or report about THD
|
exist (Relay_log_info::save_temporary_tables) or report about THD
|
||||||
|
Reference in New Issue
Block a user