test of updating and fetching from the same table check (BUG##5157)
mysql-test/r/lowercase_view.result: test of updating and fetching from the same table check mysql-test/r/view.result: test of updating and fetching from the same table check mysql-test/t/lowercase_view.test: test of updating and fetching from the same table check mysql-test/t/view.test: test of updating and fetching from the same table check sql/mysql_priv.h: unique table test sql/sql_base.cc: unique table test which take into account views added sql/sql_delete.cc: unique table test which take into account views added sql/sql_insert.cc: unique table test which take into account views added sql/sql_parse.cc: unique table test which take into account views added sql/sql_update.cc: unique table test which take into account views added sql/sql_view.cc: unique table test which take into account views added sql/table.h: save next independent (do not belong to current view) table
This commit is contained in:
parent
c647f600af
commit
7de077f7df
@ -1,3 +1,5 @@
|
||||
drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||
drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||
drop database if exists MySQLTest;
|
||||
create database MySQLTest;
|
||||
use MySQLTest;
|
||||
@ -8,3 +10,15 @@ Table Create Table
|
||||
vie CREATE VIEW `mysqltest`.`vie` AS select `mysqltest`.`tab`.`Field` AS `Field` from `mysqltest`.`tab`
|
||||
drop database MySQLTest;
|
||||
use test;
|
||||
create table t1Aa (col1 int);
|
||||
create table t2Aa (col1 int);
|
||||
create view v1Aa as select * from t1Aa;
|
||||
create view v2Aa as select * from v1Aa;
|
||||
update v2aA set col1 = (select max(col1) from v1aA);
|
||||
ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
|
||||
delete from v2aA where col1 = (select max(col1) from v1aA);
|
||||
ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
|
||||
insert into v2aA values ((select max(col1) from v1aA));
|
||||
ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
|
||||
drop view v2Aa,v1Aa;
|
||||
drop table t1Aa,t2Aa;
|
||||
|
@ -1270,3 +1270,15 @@ s1
|
||||
7
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
create view v1 as select * from t1;
|
||||
create view v2 as select * from v1;
|
||||
update v2 set col1 = (select max(col1) from v1);
|
||||
ERROR HY000: You can't specify target table 'v2' for update in FROM clause
|
||||
delete from v2 where col1 = (select max(col1) from v1);
|
||||
ERROR HY000: You can't specify target table 'v2' for update in FROM clause
|
||||
insert into v2 values ((select max(col1) from v1));
|
||||
ERROR HY000: You can't specify target table 'v2' for update in FROM clause
|
||||
drop view v2,v1;
|
||||
drop table t1,t2;
|
||||
|
@ -1,8 +1,12 @@
|
||||
--disable_warnings
|
||||
drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||
drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||
drop database if exists MySQLTest;
|
||||
--enable_warnings
|
||||
|
||||
|
||||
#
|
||||
# different cases in VIEW
|
||||
#
|
||||
create database MySQLTest;
|
||||
use MySQLTest;
|
||||
create table TaB (Field int);
|
||||
@ -10,3 +14,21 @@ create view ViE as select * from TAb;
|
||||
show create table VIe;
|
||||
drop database MySQLTest;
|
||||
use test;
|
||||
|
||||
#
|
||||
# test of updating and fetching from the same table check
|
||||
#
|
||||
create table t1Aa (col1 int);
|
||||
create table t2Aa (col1 int);
|
||||
create view v1Aa as select * from t1Aa;
|
||||
create view v2Aa as select * from v1Aa;
|
||||
-- error 1093
|
||||
update v2aA set col1 = (select max(col1) from v1aA);
|
||||
#update v2aA,t2aA set v2aA.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1;
|
||||
-- error 1093
|
||||
delete from v2aA where col1 = (select max(col1) from v1aA);
|
||||
#delete v2aA from v2aA,t2aA where (select max(col1) from v1aA) > 0 and v2aA.col1 = t2aA.col1;
|
||||
-- error 1093
|
||||
insert into v2aA values ((select max(col1) from v1aA));
|
||||
drop view v2Aa,v1Aa;
|
||||
drop table t1Aa,t2Aa;
|
||||
|
@ -1230,3 +1230,21 @@ insert into v1 values (1) on duplicate key update s1 = 7;
|
||||
select * from t1;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# test of updating and fetching from the same table check
|
||||
#
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
create view v1 as select * from t1;
|
||||
create view v2 as select * from v1;
|
||||
-- error 1093
|
||||
update v2 set col1 = (select max(col1) from v1);
|
||||
#update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
|
||||
-- error 1093
|
||||
delete from v2 where col1 = (select max(col1) from v1);
|
||||
#delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1;
|
||||
-- error 1093
|
||||
insert into v2 values ((select max(col1) from v1));
|
||||
drop view v2,v1;
|
||||
drop table t1,t2;
|
||||
|
@ -772,6 +772,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
uint offset_to_list,
|
||||
const char *db_name,
|
||||
const char *table_name);
|
||||
bool unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
|
||||
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||
void close_temporary(TABLE *table, bool delete_table=1);
|
||||
|
@ -574,16 +574,80 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
const char *db_name,
|
||||
const char *table_name)
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
if (!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name))
|
||||
break;
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_cache_key, db_name) &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_name, table_name)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Test that table is unique
|
||||
|
||||
SYNOPSIS
|
||||
unique_table()
|
||||
table table which should be chaked
|
||||
table_list list of tables
|
||||
|
||||
RETURN
|
||||
TRUE test failed
|
||||
FALSE table is unique
|
||||
*/
|
||||
|
||||
bool unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
|
||||
{
|
||||
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
|
||||
const char *d_name= table->db, *t_name= table->real_name;
|
||||
if (table->view)
|
||||
{
|
||||
/* it is view and table opened */
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
strmov(t_name_buff, table->table->table_name);
|
||||
my_casedn_str(files_charset_info, t_name_buff);
|
||||
t_name= t_name_buff;
|
||||
strmov(d_name_buff, table->table->table_cache_key);
|
||||
my_casedn_str(files_charset_info, d_name_buff);
|
||||
d_name= d_name_buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_name= table->table->table_cache_key;
|
||||
t_name= table->table->table_name;
|
||||
}
|
||||
if (d_name == 0)
|
||||
{
|
||||
/* it's temporary table */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return find_table_in_global_list(table_list, d_name, t_name);
|
||||
}
|
||||
|
||||
|
||||
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
|
||||
{
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
|
@ -282,8 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
if (unique_table(table_list, table_list->next_independent()))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
DBUG_RETURN(-1);
|
||||
|
@ -599,8 +599,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
if (unique_table(table_list, table_list->next_independent()))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
DBUG_RETURN(-1);
|
||||
|
@ -2393,17 +2393,7 @@ mysql_execute_command(THD *thd)
|
||||
if (select_lex->item_list.elements) // With select
|
||||
{
|
||||
select_result *result;
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts
|
||||
of query
|
||||
*/
|
||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
|
||||
find_table_in_global_list(select_tables, create_table->db,
|
||||
create_table->real_name))
|
||||
{
|
||||
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
|
||||
goto create_error;
|
||||
}
|
||||
|
||||
if (select_tables &&
|
||||
check_table_access(thd, SELECT_ACL, select_tables, 0))
|
||||
goto create_error; // Error message is given
|
||||
@ -2412,6 +2402,17 @@ mysql_execute_command(THD *thd)
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, select_tables)))
|
||||
{
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts
|
||||
of query
|
||||
*/
|
||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
|
||||
unique_table(create_table, select_tables))
|
||||
{
|
||||
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
|
||||
goto create_error;
|
||||
}
|
||||
|
||||
if ((result= new select_create(create_table,
|
||||
&lex->create_info,
|
||||
lex->create_list,
|
||||
@ -2767,16 +2768,18 @@ unsent_create_error:
|
||||
select_result *result;
|
||||
unit->set_limit(select_lex, select_lex);
|
||||
|
||||
// is table which we are changing used somewhere in other parts of query
|
||||
if (find_table_in_global_list(all_tables->next_global,
|
||||
first_table->db, first_table->real_name))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
select_lex->options |= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables)))
|
||||
{
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts of
|
||||
query
|
||||
*/
|
||||
if (unique_table(first_table, all_tables->next_independent()))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
select_lex->options |= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
|
||||
if ((res= mysql_insert_select_prepare(thd)))
|
||||
break;
|
||||
if ((result= new select_insert(first_table, first_table->table,
|
||||
|
@ -496,8 +496,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/* Check that we are not using table that we are updating in a sub select */
|
||||
if (find_table_in_global_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
if (unique_table(table_list, table_list->next_independent()))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
DBUG_RETURN(-1);
|
||||
@ -788,7 +787,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
find_table_in_global_list(update_tables, table_ref->db,
|
||||
find_table_in_local_list(update_tables, table_ref->db,
|
||||
table_ref->real_name))
|
||||
table->no_cache= 1; // Disable row cache
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
if (lex->spfuns.array.buffer)
|
||||
hash_free(&lex->spfuns);
|
||||
|
||||
old_next= table->next_global;
|
||||
old_next= table->old_next= table->next_global;
|
||||
if ((table->next_global= lex->query_tables))
|
||||
table->next_global->prev_global= &table->next_global;
|
||||
|
||||
|
@ -217,6 +217,8 @@ typedef struct st_table_list
|
||||
st_table_list *ancestor;
|
||||
/* most upper view this table belongs to */
|
||||
st_table_list *belong_to_view;
|
||||
/* next_global before adding VIEW tables */
|
||||
st_table_list *old_next;
|
||||
Item *where; /* VIEW WHERE clause condition */
|
||||
LEX_STRING query; /* text of (CRETE/SELECT) statement */
|
||||
LEX_STRING md5; /* md5 of query tesxt */
|
||||
@ -260,6 +262,12 @@ typedef struct st_table_list
|
||||
bool setup_ancestor(THD *thd, Item **conds);
|
||||
bool placeholder() {return derived || view; }
|
||||
void print(THD *thd, String *str);
|
||||
inline st_table_list *next_independent()
|
||||
{
|
||||
if (view)
|
||||
return old_next;
|
||||
return next_global;
|
||||
}
|
||||
} TABLE_LIST;
|
||||
|
||||
class Item;
|
||||
|
Loading…
x
Reference in New Issue
Block a user