mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/dlenev/src/mysql-5.0-bg11896 mysql-test/t/sp-error.test: Auto merged mysql-test/t/trigger.test: Auto merged sql/sql_base.cc: Auto merged mysql-test/r/trigger.result: Manual merge. sql/share/errmsg.txt: Manual merge.
This commit is contained in:
@ -299,6 +299,36 @@ lock tables t1 read, mysql.proc read|
|
||||
unlock tables|
|
||||
lock tables mysql.proc write|
|
||||
unlock tables|
|
||||
drop function if exists f1|
|
||||
create function f1(i int) returns int
|
||||
begin
|
||||
insert into t1 (val) values (i);
|
||||
return 0;
|
||||
end|
|
||||
select val, f1(val) from t1|
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select val, f1(val) from t1 as tab|
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select * from t1|
|
||||
val x
|
||||
42 3.1
|
||||
19 1.2
|
||||
update t1 set val= f1(val)|
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select * from t1|
|
||||
val x
|
||||
42 3.1
|
||||
19 1.2
|
||||
select f1(17)|
|
||||
f1(17)
|
||||
0
|
||||
select * from t1|
|
||||
val x
|
||||
42 3.1
|
||||
19 1.2
|
||||
17 NULL
|
||||
delete from t1 where val= 17|
|
||||
drop function f1|
|
||||
create procedure bug1965()
|
||||
begin
|
||||
declare c cursor for select val from t1 order by valname;
|
||||
|
@ -697,3 +697,44 @@ c1 c2
|
||||
3 NULL
|
||||
drop procedure bug11587;
|
||||
drop table t1;
|
||||
create table t1 (f1 integer);
|
||||
create table t2 (f2 integer);
|
||||
create trigger t1_ai after insert on t1
|
||||
for each row insert into t2 values (new.f1+1);
|
||||
create trigger t2_ai after insert on t2
|
||||
for each row insert into t1 values (new.f2+1);
|
||||
insert into t1 values (1);
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select * from t1;
|
||||
f1
|
||||
1
|
||||
select * from t2;
|
||||
f2
|
||||
2
|
||||
drop trigger t1_ai;
|
||||
drop trigger t2_ai;
|
||||
create trigger t1_bu before update on t1
|
||||
for each row insert into t1 values (2);
|
||||
update t1 set f1= 10;
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select * from t1;
|
||||
f1
|
||||
1
|
||||
drop trigger t1_bu;
|
||||
create trigger t1_bu before update on t1
|
||||
for each row delete from t1 where f1=new.f1;
|
||||
update t1 set f1= 10;
|
||||
ERROR HY000: Can't update table 't1' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
|
||||
select * from t1;
|
||||
f1
|
||||
1
|
||||
drop trigger t1_bu;
|
||||
create trigger t1_bi before insert on t1
|
||||
for each row set new.f1=(select sum(f1) from t1);
|
||||
insert into t1 values (3);
|
||||
select * from t1;
|
||||
f1
|
||||
1
|
||||
1
|
||||
drop trigger t1_bi;
|
||||
drop tables t1, t2;
|
||||
|
@ -409,6 +409,35 @@ lock tables mysql.proc write|
|
||||
unlock tables|
|
||||
|
||||
|
||||
#
|
||||
# Check that in functions we don't allow to update tables which
|
||||
# are used by statements which invoke these functions.
|
||||
#
|
||||
--disable_warnings
|
||||
drop function if exists f1|
|
||||
--enable_warnings
|
||||
create function f1(i int) returns int
|
||||
begin
|
||||
insert into t1 (val) values (i);
|
||||
return 0;
|
||||
end|
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
select val, f1(val) from t1|
|
||||
# Table alias should not matter
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
select val, f1(val) from t1 as tab|
|
||||
select * from t1|
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
update t1 set val= f1(val)|
|
||||
select * from t1|
|
||||
# But this should be OK
|
||||
select f1(17)|
|
||||
select * from t1|
|
||||
# Cleanup
|
||||
delete from t1 where val= 17|
|
||||
drop function f1|
|
||||
|
||||
|
||||
#
|
||||
# BUG#1965
|
||||
#
|
||||
|
@ -729,3 +729,39 @@ select * from t1;
|
||||
|
||||
drop procedure bug11587;
|
||||
drop table t1;
|
||||
|
||||
# Test for bug #11896 "Partial locking in case of recursive trigger
|
||||
# definitions". Recursion in triggers should not be allowed.
|
||||
# We also should not allow to change tables which are used in
|
||||
# statements invoking this trigger.
|
||||
create table t1 (f1 integer);
|
||||
create table t2 (f2 integer);
|
||||
create trigger t1_ai after insert on t1
|
||||
for each row insert into t2 values (new.f1+1);
|
||||
create trigger t2_ai after insert on t2
|
||||
for each row insert into t1 values (new.f2+1);
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
insert into t1 values (1);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
drop trigger t1_ai;
|
||||
drop trigger t2_ai;
|
||||
create trigger t1_bu before update on t1
|
||||
for each row insert into t1 values (2);
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
update t1 set f1= 10;
|
||||
select * from t1;
|
||||
drop trigger t1_bu;
|
||||
create trigger t1_bu before update on t1
|
||||
for each row delete from t1 where f1=new.f1;
|
||||
--error ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
update t1 set f1= 10;
|
||||
select * from t1;
|
||||
drop trigger t1_bu;
|
||||
# This should work tough
|
||||
create trigger t1_bi before insert on t1
|
||||
for each row set new.f1=(select sum(f1) from t1);
|
||||
insert into t1 values (3);
|
||||
select * from t1;
|
||||
drop trigger t1_bi;
|
||||
drop tables t1, t2;
|
||||
|
@ -5397,3 +5397,5 @@ ER_XAER_DUPID XAE08
|
||||
eng "XAER_DUPID: The XID already exists"
|
||||
ER_DATETIME_FUNCTION_OVERFLOW 22008
|
||||
eng "Datetime function: %-.32s field overflow"
|
||||
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
|
||||
eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
|
||||
|
@ -1043,35 +1043,61 @@ 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->key_length == key_length &&
|
||||
!memcmp(table->s->table_cache_key, key, key_length) &&
|
||||
!my_strcasecmp(system_charset_info, table->alias, alias) &&
|
||||
table->query_id != thd->query_id && /* skip tables already used */
|
||||
!(thd->prelocked_mode && table->query_id))
|
||||
!memcmp(table->s->table_cache_key, key, key_length))
|
||||
{
|
||||
int distance= ((int) table->reginfo.lock_type -
|
||||
(int) table_list->lock_type);
|
||||
/*
|
||||
Find a table that either has the exact lock type requested,
|
||||
or has the best suitable lock. In case there is no locked
|
||||
table that has an equal or higher lock than requested,
|
||||
we us the closest matching lock to be able to produce an error
|
||||
message about wrong lock mode on the table. The best_table is changed
|
||||
if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.
|
||||
|
||||
distance < 0 - No suitable lock found
|
||||
distance > 0 - we have lock mode higher then we require
|
||||
distance == 0 - we have lock mode exactly which we need
|
||||
*/
|
||||
if (best_distance < 0 && distance > best_distance ||
|
||||
distance >= 0 && distance < best_distance)
|
||||
if (check_if_used && table->query_id &&
|
||||
table->query_id != thd->query_id)
|
||||
{
|
||||
best_distance= distance;
|
||||
best_table= table;
|
||||
if (best_distance == 0) // Found perfect lock
|
||||
break;
|
||||
/*
|
||||
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);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
|
||||
table->query_id != thd->query_id && /* skip tables already used */
|
||||
!(thd->prelocked_mode && table->query_id))
|
||||
{
|
||||
int distance= ((int) table->reginfo.lock_type -
|
||||
(int) table_list->lock_type);
|
||||
/*
|
||||
Find a table that either has the exact lock type requested,
|
||||
or has the best suitable lock. In case there is no locked
|
||||
table that has an equal or higher lock than requested,
|
||||
we us the closest matching lock to be able to produce an error
|
||||
message about wrong lock mode on the table. The best_table
|
||||
is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.
|
||||
|
||||
distance < 0 - No suitable lock found
|
||||
distance > 0 - we have lock mode higher then we require
|
||||
distance == 0 - we have lock mode exactly which we need
|
||||
*/
|
||||
if (best_distance < 0 && distance > best_distance ||
|
||||
distance >= 0 && distance < best_distance)
|
||||
{
|
||||
best_distance= distance;
|
||||
best_table= table;
|
||||
if (best_distance == 0 && !check_if_used)
|
||||
{
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user