diff options
author | unknown <bell@sanja.is.com.ua> | 2004-09-08 13:39:15 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-09-08 13:39:15 +0300 |
commit | 6c2330407f99b0bab1db68ec38789fc10a3518ec (patch) | |
tree | 42e71f47652f97532ac4741a570233064060593d /sql | |
parent | eb72c28b9b8e7fe785e918cc1c366b4fce6fa8f6 (diff) | |
download | mariadb-git-6c2330407f99b0bab1db68ec38789fc10a3518ec.tar.gz |
check that table used in multi-update is unique added (BUG#5455)
mysql-test/r/multi_update.result:
multi* unique updating table check
mysql-test/t/multi_update.test:
multi* unique updating table check
sql/sql_lex.cc:
new method to check table only in subqueries
sql/sql_lex.h:
new method to check table only in subqueries
sql/sql_parse.cc:
used new method to check table only in subqueries
sql/sql_update.cc:
check that table is unique added
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_lex.cc | 22 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 23 | ||||
-rw-r--r-- | sql/sql_update.cc | 26 |
4 files changed, 52 insertions, 20 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index fab047002ad..36af3003487 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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()) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7342902c086..dffe7bcb2b0 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 39b94362269..dd57f37473c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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; } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index db4edff4fa1..b6cd0d967e9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -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; } |