Loading mysql-test/r/trigger.result +12 −0 Original line number Diff line number Diff line Loading @@ -1173,4 +1173,16 @@ TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2; ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) DROP TABLE t1; DROP TABLE t2; drop table if exists t1; create table t1 (i int, j int key); insert into t1 values (1,1), (2,2), (3,3); create trigger t1_bu before update on t1 for each row set new.j = new.j + 10; update t1 set i= i+ 10 where j > 2; select * from t1; i j 1 1 2 2 13 13 drop table t1; End of 5.0 tests mysql-test/t/trigger.test +19 −0 Original line number Diff line number Diff line Loading @@ -1421,4 +1421,23 @@ DROP TABLE t1; DROP TABLE t2; # # Bug#20670 "UPDATE using key and invoking trigger that modifies # this key does not stop" # --disable_warnings drop table if exists t1; --enable_warnings create table t1 (i int, j int key); insert into t1 values (1,1), (2,2), (3,3); create trigger t1_bu before update on t1 for each row set new.j = new.j + 10; # This should not work indefinitely and should cause # expected result update t1 set i= i+ 10 where j > 2; select * from t1; drop table t1; --echo End of 5.0 tests sql/key.cc +20 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ /* Functions to handle keys and fields in forms */ #include "mysql_priv.h" #include "sql_trigger.h" /* ** Search after with key field is. If no key starts with field test Loading Loading @@ -342,12 +343,24 @@ void key_unpack(String *to,TABLE *table,uint idx) /* Return 1 if any field in a list is part of key or the key uses a field that is automaticly updated (like a timestamp) Check if key uses field that is listed in passed field list or is automatically updated (like a timestamp) or can be updated by before update trigger defined on the table. SYNOPSIS is_key_used() table TABLE object with which keys and fields are associated. idx Key to be checked. fields List of fields to be checked. RETURN VALUE TRUE Key uses field which meets one the above conditions FALSE Otherwise */ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) bool is_key_used(TABLE *table, uint idx, List<Item> &fields) { Table_triggers_list *triggers= table->triggers; List_iterator_fast<Item> f(fields); KEY_PART_INFO *key_part,*key_part_end; for (key_part=table->key_info[idx].key_part,key_part_end=key_part+ Loading @@ -366,6 +379,9 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) if (key_part->field->eq(field->field)) return 1; } if (triggers && triggers->is_updated_in_before_update_triggers(key_part->field)) return 1; } /* Loading @@ -374,7 +390,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) */ if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY && (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) return check_if_key_used(table, table->s->primary_key, fields); return is_key_used(table, table->s->primary_key, fields); return 0; } Loading sql/mysql_priv.h +1 −1 Original line number Diff line number Diff line Loading @@ -1113,7 +1113,7 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info, uint key_length); bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length); void key_unpack(String *to,TABLE *form,uint index); bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields); bool is_key_used(TABLE *table, uint idx, List<Item> &fields); int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length); bool init_errmessage(void); Loading sql/opt_range.cc +8 −8 Original line number Diff line number Diff line Loading @@ -6127,42 +6127,42 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) } bool QUICK_SELECT_I::check_if_keys_used(List<Item> *fields) bool QUICK_SELECT_I::is_keys_used(List<Item> *fields) { return check_if_key_used(head, index, *fields); return is_key_used(head, index, *fields); } bool QUICK_INDEX_MERGE_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_INDEX_MERGE_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { if (check_if_key_used(head, quick->index, *fields)) if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } bool QUICK_ROR_INTERSECT_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { if (check_if_key_used(head, quick->index, *fields)) if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_ROR_UNION_SELECT::is_keys_used(List<Item> *fields) { QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); while ((quick= it++)) { if (quick->check_if_keys_used(fields)) if (quick->is_keys_used(fields)) return 1; } return 0; Loading Loading
mysql-test/r/trigger.result +12 −0 Original line number Diff line number Diff line Loading @@ -1173,4 +1173,16 @@ TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2; ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60) DROP TABLE t1; DROP TABLE t2; drop table if exists t1; create table t1 (i int, j int key); insert into t1 values (1,1), (2,2), (3,3); create trigger t1_bu before update on t1 for each row set new.j = new.j + 10; update t1 set i= i+ 10 where j > 2; select * from t1; i j 1 1 2 2 13 13 drop table t1; End of 5.0 tests
mysql-test/t/trigger.test +19 −0 Original line number Diff line number Diff line Loading @@ -1421,4 +1421,23 @@ DROP TABLE t1; DROP TABLE t2; # # Bug#20670 "UPDATE using key and invoking trigger that modifies # this key does not stop" # --disable_warnings drop table if exists t1; --enable_warnings create table t1 (i int, j int key); insert into t1 values (1,1), (2,2), (3,3); create trigger t1_bu before update on t1 for each row set new.j = new.j + 10; # This should not work indefinitely and should cause # expected result update t1 set i= i+ 10 where j > 2; select * from t1; drop table t1; --echo End of 5.0 tests
sql/key.cc +20 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ /* Functions to handle keys and fields in forms */ #include "mysql_priv.h" #include "sql_trigger.h" /* ** Search after with key field is. If no key starts with field test Loading Loading @@ -342,12 +343,24 @@ void key_unpack(String *to,TABLE *table,uint idx) /* Return 1 if any field in a list is part of key or the key uses a field that is automaticly updated (like a timestamp) Check if key uses field that is listed in passed field list or is automatically updated (like a timestamp) or can be updated by before update trigger defined on the table. SYNOPSIS is_key_used() table TABLE object with which keys and fields are associated. idx Key to be checked. fields List of fields to be checked. RETURN VALUE TRUE Key uses field which meets one the above conditions FALSE Otherwise */ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) bool is_key_used(TABLE *table, uint idx, List<Item> &fields) { Table_triggers_list *triggers= table->triggers; List_iterator_fast<Item> f(fields); KEY_PART_INFO *key_part,*key_part_end; for (key_part=table->key_info[idx].key_part,key_part_end=key_part+ Loading @@ -366,6 +379,9 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) if (key_part->field->eq(field->field)) return 1; } if (triggers && triggers->is_updated_in_before_update_triggers(key_part->field)) return 1; } /* Loading @@ -374,7 +390,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) */ if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY && (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) return check_if_key_used(table, table->s->primary_key, fields); return is_key_used(table, table->s->primary_key, fields); return 0; } Loading
sql/mysql_priv.h +1 −1 Original line number Diff line number Diff line Loading @@ -1113,7 +1113,7 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info, uint key_length); bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length); void key_unpack(String *to,TABLE *form,uint index); bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields); bool is_key_used(TABLE *table, uint idx, List<Item> &fields); int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length); bool init_errmessage(void); Loading
sql/opt_range.cc +8 −8 Original line number Diff line number Diff line Loading @@ -6127,42 +6127,42 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) } bool QUICK_SELECT_I::check_if_keys_used(List<Item> *fields) bool QUICK_SELECT_I::is_keys_used(List<Item> *fields) { return check_if_key_used(head, index, *fields); return is_key_used(head, index, *fields); } bool QUICK_INDEX_MERGE_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_INDEX_MERGE_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { if (check_if_key_used(head, quick->index, *fields)) if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } bool QUICK_ROR_INTERSECT_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { if (check_if_key_used(head, quick->index, *fields)) if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List<Item> *fields) bool QUICK_ROR_UNION_SELECT::is_keys_used(List<Item> *fields) { QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); while ((quick= it++)) { if (quick->check_if_keys_used(fields)) if (quick->is_keys_used(fields)) return 1; } return 0; Loading