Merge from 5.0-bugteam
This commit is contained in:
commit
70fdfcb6a2
@ -1960,6 +1960,26 @@ select * from t2;
|
||||
s1
|
||||
drop table t1;
|
||||
drop temporary table t2;
|
||||
#------------------------------------------------------------------------
|
||||
# Bug#39953 Triggers are not working properly with multi table updates
|
||||
#------------------------------------------------------------------------
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TRIGGER IF EXISTS t_insert;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1 (a int, date_insert timestamp, PRIMARY KEY (a));
|
||||
INSERT INTO t1 (a) VALUES (2),(5);
|
||||
CREATE TABLE t2 (a int, b int, PRIMARY KEY (a));
|
||||
CREATE TRIGGER t_insert AFTER INSERT ON t2 FOR EACH ROW BEGIN UPDATE t1,t2 SET
|
||||
date_insert=NOW() WHERE t1.a=t2.b AND t2.a=NEW.a; END |
|
||||
INSERT INTO t2 (a,b) VALUES (1,2);
|
||||
DROP TRIGGER t_insert;
|
||||
CREATE TRIGGER t_insert AFTER INSERT ON t2 FOR EACH ROW BEGIN UPDATE t1,t2 SET
|
||||
date_insert=NOW(),b=b+1 WHERE t1.a=t2.b AND t2.a=NEW.a; END |
|
||||
INSERT INTO t2 (a,b) VALUES (3,5);
|
||||
ERROR HY000: Can't update table 't2' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
DROP TABLE t1;
|
||||
DROP TRIGGER t_insert;
|
||||
DROP TABLE t2;
|
||||
End of 5.0 tests
|
||||
drop table if exists table_25411_a;
|
||||
drop table if exists table_25411_b;
|
||||
|
@ -2218,6 +2218,39 @@ select * from t1;
|
||||
select * from t2;
|
||||
drop table t1;
|
||||
drop temporary table t2;
|
||||
|
||||
--echo #------------------------------------------------------------------------
|
||||
--echo # Bug#39953 Triggers are not working properly with multi table updates
|
||||
--echo #------------------------------------------------------------------------
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TRIGGER IF EXISTS t_insert;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (a int, date_insert timestamp, PRIMARY KEY (a));
|
||||
INSERT INTO t1 (a) VALUES (2),(5);
|
||||
CREATE TABLE t2 (a int, b int, PRIMARY KEY (a));
|
||||
DELIMITER |;
|
||||
CREATE TRIGGER t_insert AFTER INSERT ON t2 FOR EACH ROW BEGIN UPDATE t1,t2 SET
|
||||
date_insert=NOW() WHERE t1.a=t2.b AND t2.a=NEW.a; END |
|
||||
DELIMITER ;|
|
||||
INSERT INTO t2 (a,b) VALUES (1,2);
|
||||
|
||||
DROP TRIGGER t_insert;
|
||||
|
||||
DELIMITER |;
|
||||
CREATE TRIGGER t_insert AFTER INSERT ON t2 FOR EACH ROW BEGIN UPDATE t1,t2 SET
|
||||
date_insert=NOW(),b=b+1 WHERE t1.a=t2.b AND t2.a=NEW.a; END |
|
||||
DELIMITER ;|
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
INSERT INTO t2 (a,b) VALUES (3,5);
|
||||
|
||||
DROP TABLE t1;
|
||||
DROP TRIGGER t_insert;
|
||||
DROP TABLE t2;
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
#
|
||||
|
@ -2600,27 +2600,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
{ // Using table locks
|
||||
TABLE *best_table= 0;
|
||||
int best_distance= INT_MIN;
|
||||
bool check_if_used= thd->prelocked_mode &&
|
||||
((int) table_list->lock_type >=
|
||||
(int) TL_WRITE_ALLOW_WRITE);
|
||||
for (table=thd->open_tables; table ; table=table->next)
|
||||
{
|
||||
if (table->s->table_cache_key.length == key_length &&
|
||||
!memcmp(table->s->table_cache_key.str, key, key_length))
|
||||
{
|
||||
if (check_if_used && table->query_id &&
|
||||
table->query_id != thd->query_id)
|
||||
{
|
||||
/*
|
||||
If we are in stored function or trigger we should ensure that
|
||||
we won't change table that is already used by calling statement.
|
||||
So if we are opening table for writing, we should check that it
|
||||
is not already open by some calling stamement.
|
||||
*/
|
||||
my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
|
||||
table->s->table_name.str);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
/*
|
||||
When looking for a usable TABLE, ignore MERGE children, as they
|
||||
belong to their parent and cannot be used explicitly.
|
||||
@ -2649,13 +2633,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
{
|
||||
best_distance= distance;
|
||||
best_table= table;
|
||||
if (best_distance == 0 && !check_if_used)
|
||||
if (best_distance == 0)
|
||||
{
|
||||
/*
|
||||
If we have found perfect match and we don't need to check that
|
||||
table is not used by one of calling statements (assuming that
|
||||
we are inside of function or trigger) we can finish iterating
|
||||
through open tables list.
|
||||
We have found a perfect match and can finish iterating
|
||||
through open tables list. Check for table use conflict
|
||||
between calling statement and SP/trigger is done in
|
||||
lock_tables().
|
||||
*/
|
||||
break;
|
||||
}
|
||||
@ -4888,9 +4872,9 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
|
||||
lock_flags Flags passed to mysql_lock_table
|
||||
|
||||
NOTE
|
||||
This function don't do anything like SP/SF/views/triggers analysis done
|
||||
in open_tables(). It is intended for opening of only one concrete table.
|
||||
And used only in special contexts.
|
||||
This function doesn't do anything like SP/SF/views/triggers analysis done
|
||||
in open_table()/lock_tables(). It is intended for opening of only one
|
||||
concrete table. And used only in special contexts.
|
||||
|
||||
RETURN VALUES
|
||||
table Opened table
|
||||
@ -4908,6 +4892,9 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
||||
bool refresh;
|
||||
DBUG_ENTER("open_ltable");
|
||||
|
||||
/* should not be used in a prelocked_mode context, see NOTE above */
|
||||
DBUG_ASSERT(!thd->prelocked_mode);
|
||||
|
||||
thd_proc_info(thd, "Opening table");
|
||||
thd->current_tablenr= 0;
|
||||
/* open_ltable can be used only for BASIC TABLEs */
|
||||
@ -5374,8 +5361,29 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
|
||||
table && table != first_not_own;
|
||||
table= table->next_global)
|
||||
{
|
||||
if (!table->placeholder() &&
|
||||
check_lock_and_start_stmt(thd, table->table, table->lock_type))
|
||||
if (table->placeholder())
|
||||
continue;
|
||||
|
||||
/*
|
||||
In a stored function or trigger we should ensure that we won't change
|
||||
a table that is already used by the calling statement.
|
||||
*/
|
||||
if (thd->prelocked_mode &&
|
||||
table->lock_type >= TL_WRITE_ALLOW_WRITE)
|
||||
{
|
||||
for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
|
||||
{
|
||||
if (table->table->s == opentab->s && opentab->query_id &&
|
||||
table->table->query_id != opentab->query_id)
|
||||
{
|
||||
my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
|
||||
table->table->s->table_name.str);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user