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;
|
drop database if exists MySQLTest;
|
||||||
create database MySQLTest;
|
create database MySQLTest;
|
||||||
use 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`
|
vie CREATE VIEW `mysqltest`.`vie` AS select `mysqltest`.`tab`.`Field` AS `Field` from `mysqltest`.`tab`
|
||||||
drop database MySQLTest;
|
drop database MySQLTest;
|
||||||
use test;
|
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
|
7
|
||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1;
|
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
|
--disable_warnings
|
||||||
|
drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||||
|
drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
|
||||||
drop database if exists MySQLTest;
|
drop database if exists MySQLTest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
|
#
|
||||||
|
# different cases in VIEW
|
||||||
|
#
|
||||||
create database MySQLTest;
|
create database MySQLTest;
|
||||||
use MySQLTest;
|
use MySQLTest;
|
||||||
create table TaB (Field int);
|
create table TaB (Field int);
|
||||||
@ -10,3 +14,21 @@ create view ViE as select * from TAb;
|
|||||||
show create table VIe;
|
show create table VIe;
|
||||||
drop database MySQLTest;
|
drop database MySQLTest;
|
||||||
use test;
|
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;
|
select * from t1;
|
||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1;
|
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,
|
uint offset_to_list,
|
||||||
const char *db_name,
|
const char *db_name,
|
||||||
const char *table_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);
|
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);
|
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||||
void close_temporary(TABLE *table, bool delete_table=1);
|
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 *db_name,
|
||||||
const char *table_name)
|
const char *table_name)
|
||||||
{
|
{
|
||||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
if (lower_case_table_names)
|
||||||
{
|
{
|
||||||
if (!strcmp(table->db, db_name) &&
|
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||||
!strcmp(table->real_name, table_name))
|
{
|
||||||
break;
|
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;
|
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)
|
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
|
||||||
{
|
{
|
||||||
char key[MAX_DBKEY_LENGTH];
|
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");
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
if (find_table_in_global_list(table_list->next_global,
|
if (unique_table(table_list, table_list->next_independent()))
|
||||||
table_list->db, table_list->real_name))
|
|
||||||
{
|
{
|
||||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||||
DBUG_RETURN(-1);
|
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))))
|
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
if (find_table_in_global_list(table_list->next_global,
|
if (unique_table(table_list, table_list->next_independent()))
|
||||||
table_list->db, table_list->real_name))
|
|
||||||
{
|
{
|
||||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
@ -2393,17 +2393,7 @@ mysql_execute_command(THD *thd)
|
|||||||
if (select_lex->item_list.elements) // With select
|
if (select_lex->item_list.elements) // With select
|
||||||
{
|
{
|
||||||
select_result *result;
|
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 &&
|
if (select_tables &&
|
||||||
check_table_access(thd, SELECT_ACL, select_tables, 0))
|
check_table_access(thd, SELECT_ACL, select_tables, 0))
|
||||||
goto create_error; // Error message is given
|
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)))
|
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,
|
if ((result= new select_create(create_table,
|
||||||
&lex->create_info,
|
&lex->create_info,
|
||||||
lex->create_list,
|
lex->create_list,
|
||||||
@ -2767,16 +2768,18 @@ unsent_create_error:
|
|||||||
select_result *result;
|
select_result *result;
|
||||||
unit->set_limit(select_lex, select_lex);
|
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)))
|
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)))
|
if ((res= mysql_insert_select_prepare(thd)))
|
||||||
break;
|
break;
|
||||||
if ((result= new select_insert(first_table, first_table->table,
|
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);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
/* Check that we are not using table that we are updating in a sub select */
|
/* 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,
|
if (unique_table(table_list, table_list->next_independent()))
|
||||||
table_list->db, table_list->real_name))
|
|
||||||
{
|
{
|
||||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
@ -788,7 +787,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
{
|
{
|
||||||
TABLE *table=table_ref->table;
|
TABLE *table=table_ref->table;
|
||||||
if (!(tables_to_update & table->map) &&
|
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_ref->real_name))
|
||||||
table->no_cache= 1; // Disable row cache
|
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)
|
if (lex->spfuns.array.buffer)
|
||||||
hash_free(&lex->spfuns);
|
hash_free(&lex->spfuns);
|
||||||
|
|
||||||
old_next= table->next_global;
|
old_next= table->old_next= table->next_global;
|
||||||
if ((table->next_global= lex->query_tables))
|
if ((table->next_global= lex->query_tables))
|
||||||
table->next_global->prev_global= &table->next_global;
|
table->next_global->prev_global= &table->next_global;
|
||||||
|
|
||||||
|
@ -217,6 +217,8 @@ typedef struct st_table_list
|
|||||||
st_table_list *ancestor;
|
st_table_list *ancestor;
|
||||||
/* most upper view this table belongs to */
|
/* most upper view this table belongs to */
|
||||||
st_table_list *belong_to_view;
|
st_table_list *belong_to_view;
|
||||||
|
/* next_global before adding VIEW tables */
|
||||||
|
st_table_list *old_next;
|
||||||
Item *where; /* VIEW WHERE clause condition */
|
Item *where; /* VIEW WHERE clause condition */
|
||||||
LEX_STRING query; /* text of (CRETE/SELECT) statement */
|
LEX_STRING query; /* text of (CRETE/SELECT) statement */
|
||||||
LEX_STRING md5; /* md5 of query tesxt */
|
LEX_STRING md5; /* md5 of query tesxt */
|
||||||
@ -260,6 +262,12 @@ typedef struct st_table_list
|
|||||||
bool setup_ancestor(THD *thd, Item **conds);
|
bool setup_ancestor(THD *thd, Item **conds);
|
||||||
bool placeholder() {return derived || view; }
|
bool placeholder() {return derived || view; }
|
||||||
void print(THD *thd, String *str);
|
void print(THD *thd, String *str);
|
||||||
|
inline st_table_list *next_independent()
|
||||||
|
{
|
||||||
|
if (view)
|
||||||
|
return old_next;
|
||||||
|
return next_global;
|
||||||
|
}
|
||||||
} TABLE_LIST;
|
} TABLE_LIST;
|
||||||
|
|
||||||
class Item;
|
class Item;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user