Commit 24fe8535 authored by unknown's avatar unknown

Fix for bug #12198 "Temporary table aliasing does not work inside stored

functions".

We should ignore alias when we check if table was already marked as temporary
when we calculate set of tables to be prelocked. Otherwise we will erroneously
treat tables which are used in same routine and have same name but different
alias as non-temporary.


mysql-test/r/sp.result:
  Added test for bug #12198 "Temporary table aliasing does not work inside stored
  functions" and other tests which cover handling of temporary tables in prelocked
  mode.
mysql-test/t/sp.test:
  Added test for bug #12198 "Temporary table aliasing does not work inside stored
  functions" and other tests which cover handling of temporary tables in prelocked
  mode.
sql/sp_head.cc:
  sp_head::merge_table_list():
    We should ignore alias when we check if table was already marked as temporary
    when we calculate set of tables to be prelocked. Otherwise we will erroneously
    treat tables which are used in same routine and have same name but different
    alias as non-temporary.
parent 4f4ec460
...@@ -918,6 +918,11 @@ drop function if exists f5| ...@@ -918,6 +918,11 @@ drop function if exists f5|
drop function if exists f6| drop function if exists f6|
drop function if exists f7| drop function if exists f7|
drop function if exists f8| drop function if exists f8|
drop function if exists f9|
drop function if exists f10|
drop function if exists f11|
drop function if exists f12_1|
drop function if exists f12_2|
drop view if exists v0| drop view if exists v0|
drop view if exists v1| drop view if exists v1|
drop view if exists v2| drop view if exists v2|
...@@ -1087,6 +1092,62 @@ ERROR HY000: Table 't1' was not locked with LOCK TABLES ...@@ -1087,6 +1092,62 @@ ERROR HY000: Table 't1' was not locked with LOCK TABLES
select f4()| select f4()|
ERROR HY000: Table 't2' was not locked with LOCK TABLES ERROR HY000: Table 't2' was not locked with LOCK TABLES
unlock tables| unlock tables|
create function f9() returns int
begin
declare a, b int;
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
set a:= (select count(*) from t3);
set b:= (select count(*) from t3 t3_alias);
return a + b;
end|
select f9()|
f9()
6
Warnings:
Note 1051 Unknown table 't3'
select f9() from t1 limit 1|
f9()
6
create function f10() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 select id from t4;
return (select count(*) from t3);
end|
select f10()|
ERROR 42S02: Table 'test.t4' doesn't exist
create table t4 as select 1 as id|
select f10()|
f10()
1
create function f11() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
return (select count(*) from t3 as a, t3 as b);
end|
select f11()|
ERROR HY000: Can't reopen table: 'a'
select f11() from t1|
ERROR HY000: Can't reopen table: 'a'
create function f12_1() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
return f12_2();
end|
create function f12_2() returns int
return (select count(*) from t3)|
drop temporary table t3|
select f12_1()|
ERROR 42S02: Table 'test.t3' doesn't exist
select f12_1() from t1 limit 1|
ERROR 42S02: Table 'test.t3' doesn't exist
drop function f0| drop function f0|
drop function f1| drop function f1|
drop function f2| drop function f2|
...@@ -1096,11 +1157,17 @@ drop function f5| ...@@ -1096,11 +1157,17 @@ drop function f5|
drop function f6| drop function f6|
drop function f7| drop function f7|
drop function f8| drop function f8|
drop function f9|
drop function f10|
drop function f11|
drop function f12_1|
drop function f12_2|
drop view v0| drop view v0|
drop view v1| drop view v1|
drop view v2| drop view v2|
delete from t1 | delete from t1 |
delete from t2 | delete from t2 |
drop table t4|
drop table if exists fac| drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)| create table fac (n int unsigned not null primary key, f bigint unsigned)|
drop procedure if exists ifac| drop procedure if exists ifac|
......
...@@ -1154,6 +1154,11 @@ drop function if exists f5| ...@@ -1154,6 +1154,11 @@ drop function if exists f5|
drop function if exists f6| drop function if exists f6|
drop function if exists f7| drop function if exists f7|
drop function if exists f8| drop function if exists f8|
drop function if exists f9|
drop function if exists f10|
drop function if exists f11|
drop function if exists f12_1|
drop function if exists f12_2|
drop view if exists v0| drop view if exists v0|
drop view if exists v1| drop view if exists v1|
drop view if exists v2| drop view if exists v2|
...@@ -1233,8 +1238,6 @@ create function f7() returns int ...@@ -1233,8 +1238,6 @@ create function f7() returns int
select f6()| select f6()|
select id, f6() from t1| select id, f6() from t1|
# TODO Test temporary table handling
# #
# Let us test how new locking work with views # Let us test how new locking work with views
# #
...@@ -1318,6 +1321,73 @@ select * from v1, t1| ...@@ -1318,6 +1321,73 @@ select * from v1, t1|
select f4()| select f4()|
unlock tables| unlock tables|
# Tests for handling of temporary tables in functions.
#
# Unlike for permanent tables we should be able to create, use
# and drop such tables in functions.
#
# Simplest function using temporary table. It is also test case for bug
# #12198 "Temporary table aliasing does not work inside stored functions"
create function f9() returns int
begin
declare a, b int;
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
set a:= (select count(*) from t3);
set b:= (select count(*) from t3 t3_alias);
return a + b;
end|
# This will emit warning as t3 was not existing before.
select f9()|
select f9() from t1 limit 1|
# Function which uses both temporary and permanent tables.
create function f10() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 select id from t4;
return (select count(*) from t3);
end|
# Check that we don't ignore completely tables used in function
--error ER_NO_SUCH_TABLE
select f10()|
create table t4 as select 1 as id|
select f10()|
# Practical cases which we don't handle well (yet)
#
# Function which does not work because of well-known and documented
# limitation of MySQL. We can't use the several instances of the
# same temporary table in statement.
create function f11() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
return (select count(*) from t3 as a, t3 as b);
end|
--error ER_CANT_REOPEN_TABLE
select f11()|
--error ER_CANT_REOPEN_TABLE
select f11() from t1|
# We don't handle temporary tables used by nested functions well
create function f12_1() returns int
begin
drop temporary table if exists t3;
create temporary table t3 (id int);
insert into t3 values (1), (2), (3);
return f12_2();
end|
create function f12_2() returns int
return (select count(*) from t3)|
# We need clean start to get error
drop temporary table t3|
--error ER_NO_SUCH_TABLE
select f12_1()|
--error ER_NO_SUCH_TABLE
select f12_1() from t1 limit 1|
# Cleanup # Cleanup
drop function f0| drop function f0|
...@@ -1329,11 +1399,17 @@ drop function f5| ...@@ -1329,11 +1399,17 @@ drop function f5|
drop function f6| drop function f6|
drop function f7| drop function f7|
drop function f8| drop function f8|
drop function f9|
drop function f10|
drop function f11|
drop function f12_1|
drop function f12_2|
drop view v0| drop view v0|
drop view v1| drop view v1|
drop view v2| drop view v2|
delete from t1 | delete from t1 |
delete from t2 | delete from t2 |
drop table t4|
# End of non-bug tests # End of non-bug tests
......
...@@ -2992,7 +2992,14 @@ sp_restore_security_context(THD *thd, Security_context *backup) ...@@ -2992,7 +2992,14 @@ sp_restore_security_context(THD *thd, Security_context *backup)
typedef struct st_sp_table typedef struct st_sp_table
{ {
LEX_STRING qname; /* Multi-set key: db_name\0table_name\0alias\0 */ /*
Multi-set key:
db_name\0table_name\0alias\0 - for normal tables
db_name\0table_name\0 - for temporary tables
Note that in both cases we don't take last '\0' into account when
we count length of key.
*/
LEX_STRING qname;
uint db_length, table_name_length; uint db_length, table_name_length;
bool temp; /* true if corresponds to a temporary table */ bool temp; /* true if corresponds to a temporary table */
thr_lock_type lock_type; /* lock type used for prelocking */ thr_lock_type lock_type; /* lock type used for prelocking */
...@@ -3062,10 +3069,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) ...@@ -3062,10 +3069,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tname[tlen]= '\0'; tname[tlen]= '\0';
/* /*
It is safe to store pointer to table list elements in hash, We ignore alias when we check if table was already marked as temporary
since they are supposed to have the same lifetime. (and therefore should not be prelocked). Otherwise we will erroneously
treat table with same name but with different alias as non-temporary.
*/ */
if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen))) if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) ||
((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname,
tlen - alen - 1)) &&
tab->temp))
{ {
if (tab->lock_type < table->lock_type) if (tab->lock_type < table->lock_type)
tab->lock_type= table->lock_type; // Use the table with the highest lock type tab->lock_type= table->lock_type; // Use the table with the highest lock type
...@@ -3077,14 +3088,18 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) ...@@ -3077,14 +3088,18 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
{ {
if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
return FALSE; return FALSE;
tab->qname.length= tlen;
tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1);
if (!tab->qname.str)
return FALSE;
if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
lex_for_tmp_check->query_tables == table && lex_for_tmp_check->query_tables == table &&
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
tab->temp= TRUE; tab->temp= TRUE;
tab->qname.length= tlen - alen - 1;
}
else
tab->qname.length= tlen;
tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1);
if (!tab->qname.str)
return FALSE;
tab->table_name_length= table->table_name_length; tab->table_name_length= table->table_name_length;
tab->db_length= table->db_length; tab->db_length= table->db_length;
tab->lock_type= table->lock_type; tab->lock_type= table->lock_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment