mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
check that table used in multi-update is unique added (BUG#5455)
This commit is contained in:
@ -455,3 +455,10 @@ create table t3 (a int, primary key (a));
|
||||
delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a);
|
||||
ERROR 42S02: Unknown table 't3' in MULTI DELETE
|
||||
drop table t1, t2, t3;
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
|
||||
ERROR HY000: You can't specify target table 't1' for update in FROM clause
|
||||
delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1;
|
||||
ERROR HY000: You can't specify target table 't1' for update in FROM clause
|
||||
drop table t1,t2;
|
||||
|
@ -417,3 +417,14 @@ create table t3 (a int, primary key (a));
|
||||
-- error 1109
|
||||
delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a);
|
||||
drop table t1, t2, t3;
|
||||
|
||||
#
|
||||
# multi* unique updating table check
|
||||
#
|
||||
create table t1 (col1 int);
|
||||
create table t2 (col1 int);
|
||||
-- error 1093
|
||||
update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
|
||||
-- error 1093
|
||||
delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1;
|
||||
drop table t1,t2;
|
||||
|
@ -1548,6 +1548,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
|
||||
1 - found
|
||||
0 - OK (table did not found)
|
||||
*/
|
||||
|
||||
bool st_select_lex_unit::check_updateable(char *db, char *table)
|
||||
{
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
@ -1559,7 +1560,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
|
||||
|
||||
/*
|
||||
Find db.table which will be updated in this select and
|
||||
underlayed ones (except derived tables)
|
||||
underlaying ones (except derived tables)
|
||||
|
||||
SYNOPSIS
|
||||
st_select_lex::check_updateable()
|
||||
@ -1570,11 +1571,30 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
|
||||
1 - found
|
||||
0 - OK (table did not found)
|
||||
*/
|
||||
|
||||
bool st_select_lex::check_updateable(char *db, char *table)
|
||||
{
|
||||
if (find_real_table_in_list(get_table_list(), db, table))
|
||||
return 1;
|
||||
|
||||
return check_updateable_in_subqueries(db, table);
|
||||
}
|
||||
|
||||
/*
|
||||
Find db.table which will be updated in underlaying subqueries
|
||||
|
||||
SYNOPSIS
|
||||
st_select_lex::check_updateable_in_subqueries()
|
||||
db - data base name
|
||||
table - real table name
|
||||
|
||||
RETURN
|
||||
1 - found
|
||||
0 - OK (table did not found)
|
||||
*/
|
||||
|
||||
bool st_select_lex::check_updateable_in_subqueries(char *db, char *table)
|
||||
{
|
||||
for (SELECT_LEX_UNIT *un= first_inner_unit();
|
||||
un;
|
||||
un= un->next_unit())
|
||||
|
@ -517,6 +517,7 @@ public:
|
||||
}
|
||||
bool setup_ref_array(THD *thd, uint order_group_num);
|
||||
bool check_updateable(char *db, char *table);
|
||||
bool check_updateable_in_subqueries(char *db, char *table);
|
||||
void print(THD *thd, String *str);
|
||||
static void print_order(String *str, ORDER *order);
|
||||
void print_limit(THD *thd, String *str);
|
||||
|
@ -2796,24 +2796,19 @@ unsent_create_error:
|
||||
target_tbl;
|
||||
target_tbl= target_tbl->next)
|
||||
{
|
||||
target_tbl->table= target_tbl->table_list->table;
|
||||
/*
|
||||
TABLE_LIST *orig= target_tbl->table_list;
|
||||
target_tbl->table= orig->table;
|
||||
/*
|
||||
Multi-delete can't be constructed over-union => we always have
|
||||
single SELECT on top and have to check underlaying SELECTs of it
|
||||
*/
|
||||
for (SELECT_LEX_UNIT *un= lex->select_lex.first_inner_unit();
|
||||
un;
|
||||
un= un->next_unit())
|
||||
if (lex->select_lex.check_updateable_in_subqueries(orig->db,
|
||||
orig->real_name))
|
||||
{
|
||||
if (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
|
||||
un->check_updateable(target_tbl->table_list->db,
|
||||
target_tbl->table_list->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0),
|
||||
target_tbl->table_list->real_name);
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0),
|
||||
orig->real_name);
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,9 +490,8 @@ int mysql_multi_update(THD *thd,
|
||||
table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege);
|
||||
}
|
||||
|
||||
if (thd->lex->derived_tables)
|
||||
/* Assign table map values to check updatability of derived tables */
|
||||
{
|
||||
// Assign table map values to check updatability of derived tables
|
||||
uint tablenr=0;
|
||||
for (TABLE_LIST *table_list= update_list;
|
||||
table_list;
|
||||
@ -501,11 +500,12 @@ int mysql_multi_update(THD *thd,
|
||||
table_list->table->map= (table_map) 1 << tablenr;
|
||||
}
|
||||
}
|
||||
|
||||
if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
|
||||
DBUG_RETURN(-1);
|
||||
if (thd->lex->derived_tables)
|
||||
|
||||
/* Find tables used in items */
|
||||
{
|
||||
// Find tables used in items
|
||||
List_iterator_fast<Item> it(*fields);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
@ -527,7 +527,23 @@ int mysql_multi_update(THD *thd,
|
||||
if (table->timestamp_field &&
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
table->timestamp_on_update_now= 0;
|
||||
|
||||
|
||||
/* if table will be updated then check that it is unique */
|
||||
if (table->map & item_tables)
|
||||
{
|
||||
/*
|
||||
Multi-update can't be constructed over-union => we always have
|
||||
single SELECT on top and have to check underlaying SELECTs of it
|
||||
*/
|
||||
if (select_lex->check_updateable_in_subqueries(tl->db,
|
||||
tl->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0),
|
||||
tl->real_name);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (tl->derived)
|
||||
derived_tables|= table->map;
|
||||
}
|
||||
|
Reference in New Issue
Block a user