Commit 97a1418d authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1

into sanja.is.com.ua:/home/bell/mysql/bk/work-update-4.1
parents f6dba131 0badc913
...@@ -455,3 +455,10 @@ create table t3 (a int, primary key (a)); ...@@ -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); 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 ERROR 42S02: Unknown table 't3' in MULTI DELETE
drop table t1, t2, t3; 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)); ...@@ -417,3 +417,14 @@ create table t3 (a int, primary key (a));
-- error 1109 -- 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); 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; 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;
...@@ -1550,6 +1550,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) ...@@ -1550,6 +1550,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
1 - found 1 - found
0 - OK (table did not found) 0 - OK (table did not found)
*/ */
bool st_select_lex_unit::check_updateable(char *db, char *table) bool st_select_lex_unit::check_updateable(char *db, char *table)
{ {
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
...@@ -1561,7 +1562,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table) ...@@ -1561,7 +1562,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
/* /*
Find db.table which will be updated in this select and Find db.table which will be updated in this select and
underlayed ones (except derived tables) underlaying ones (except derived tables)
SYNOPSIS SYNOPSIS
st_select_lex::check_updateable() st_select_lex::check_updateable()
...@@ -1572,11 +1573,30 @@ bool st_select_lex_unit::check_updateable(char *db, char *table) ...@@ -1572,11 +1573,30 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
1 - found 1 - found
0 - OK (table did not found) 0 - OK (table did not found)
*/ */
bool st_select_lex::check_updateable(char *db, char *table) bool st_select_lex::check_updateable(char *db, char *table)
{ {
if (find_real_table_in_list(get_table_list(), db, table)) if (find_real_table_in_list(get_table_list(), db, table))
return 1; 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(); for (SELECT_LEX_UNIT *un= first_inner_unit();
un; un;
un= un->next_unit()) un= un->next_unit())
......
...@@ -517,6 +517,7 @@ public: ...@@ -517,6 +517,7 @@ public:
} }
bool setup_ref_array(THD *thd, uint order_group_num); bool setup_ref_array(THD *thd, uint order_group_num);
bool check_updateable(char *db, char *table); bool check_updateable(char *db, char *table);
bool check_updateable_in_subqueries(char *db, char *table);
void print(THD *thd, String *str); void print(THD *thd, String *str);
static void print_order(String *str, ORDER *order); static void print_order(String *str, ORDER *order);
void print_limit(THD *thd, String *str); void print_limit(THD *thd, String *str);
......
...@@ -2796,26 +2796,21 @@ unsent_create_error: ...@@ -2796,26 +2796,21 @@ unsent_create_error:
target_tbl; target_tbl;
target_tbl= target_tbl->next) 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 Multi-delete can't be constructed over-union => we always have
single SELECT on top and have to check underlaying SELECTs of it single SELECT on top and have to check underlaying SELECTs of it
*/ */
for (SELECT_LEX_UNIT *un= lex->select_lex.first_inner_unit(); if (lex->select_lex.check_updateable_in_subqueries(orig->db,
un; orig->real_name))
un= un->next_unit())
{
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), my_error(ER_UPDATE_TABLE_USED, MYF(0),
target_tbl->table_list->real_name); orig->real_name);
res= -1; res= -1;
break; break;
} }
} }
}
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count))) table_count)))
......
...@@ -490,9 +490,8 @@ int mysql_multi_update(THD *thd, ...@@ -490,9 +490,8 @@ int mysql_multi_update(THD *thd,
table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); 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; uint tablenr=0;
for (TABLE_LIST *table_list= update_list; for (TABLE_LIST *table_list= update_list;
table_list; table_list;
...@@ -501,11 +500,12 @@ int mysql_multi_update(THD *thd, ...@@ -501,11 +500,12 @@ int mysql_multi_update(THD *thd,
table_list->table->map= (table_map) 1 << tablenr; table_list->table->map= (table_map) 1 << tablenr;
} }
} }
if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0)) if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (thd->lex->derived_tables)
/* Find tables used in items */
{ {
// Find tables used in items
List_iterator_fast<Item> it(*fields); List_iterator_fast<Item> it(*fields);
Item *item; Item *item;
while ((item= it++)) while ((item= it++))
...@@ -528,6 +528,22 @@ int mysql_multi_update(THD *thd, ...@@ -528,6 +528,22 @@ int mysql_multi_update(THD *thd,
table->timestamp_field->query_id == thd->query_id) table->timestamp_field->query_id == thd->query_id)
table->timestamp_on_update_now= 0; 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) if (tl->derived)
derived_tables|= table->map; derived_tables|= table->map;
} }
......
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