Commit 6c233040 authored by unknown's avatar unknown
Browse files

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
parent eb72c28b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;
+11 −0
Original line number Diff line number Diff line
@@ -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;
+21 −1
Original line number Diff line number Diff line
@@ -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())
+1 −0
Original line number Diff line number Diff line
@@ -517,6 +517,7 @@ class st_select_lex: public st_select_lex_node
  }
  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);
+9 −14
Original line number Diff line number Diff line
@@ -2796,26 +2796,21 @@ mysql_execute_command(THD *thd)
	 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 (un->first_select()->linkage != DERIVED_TABLE_TYPE &&
	    un->check_updateable(target_tbl->table_list->db,
				 target_tbl->table_list->real_name))
      if (lex->select_lex.check_updateable_in_subqueries(orig->db,
                                                         orig->real_name))
      {
        my_error(ER_UPDATE_TABLE_USED, MYF(0),
		   target_tbl->table_list->real_name);
                 orig->real_name);
        res= -1;
        break;
      }
    }
    }

    if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
							  table_count)))
Loading