summaryrefslogtreecommitdiff
path: root/sql/key.cc
diff options
context:
space:
mode:
authorunknown <dlenev@mockturtle.local>2006-09-21 11:35:38 +0400
committerunknown <dlenev@mockturtle.local>2006-09-21 11:35:38 +0400
commit0e4dd85d67e740ddcf775ebfcebed3521b74b439 (patch)
tree2aa02574653c5f8dd623399d30c5f0397e9b4d0c /sql/key.cc
parent4355ea5a38c819cf1e98089b3d85fc628c48da46 (diff)
downloadmariadb-git-0e4dd85d67e740ddcf775ebfcebed3521b74b439.tar.gz
Fix for bug#20670 "UPDATE using key and invoking trigger that modifies
this key does not stop" (version for 5.0 only). UPDATE statement which WHERE clause used key and which invoked trigger that modified field in this key worked indefinetely. This problem occured because in cases when UPDATE statement was executed in update-on-the-fly mode (in which row is updated right during evaluation of select for WHERE clause) the new version of the row became visible to select representing WHERE clause and was updated again and again. We already solve this problem for UPDATE statements which does not invoke triggers by detecting the fact that we are going to update field in key used for scanning and performing update in two steps, during the first step we gather information about the rows to be updated and then doing actual updates. We also do this for MULTI-UPDATE and in its case we even detect situation when such fields are updated in triggers (actually we simply assume that we always update fields used in key if we have before update trigger). The fix simply extends this check which is done in check_if_key_used()/ QUICK_SELECT_I::check_if_keys_used() routine/method in such way that it also detects cases when field used in key is updated in trigger. As nice side-effect we have more precise and thus more optimal perfomance-wise check for the MULTI-UPDATE. Also check_if_key_used()/QUICK_SELECT_I::check_if_keys_used() were renamed to is_key_used()/QUICK_SELECT_I::is_keys_used() in order to better reflect that boolean predicate. Note that this check is implemented in much more elegant way in 5.1 mysql-test/r/trigger.result: Added test case for bug#20670 "UPDATE using key and invoking trigger that modifies this key does not stop". mysql-test/t/trigger.test: Added test case for bug#20670 "UPDATE using key and invoking trigger that modifies this key does not stop". sql/key.cc: Renamed check_if_key_used() to is_key_used(). Also this routine checks if key uses field which can be updated by before update trigger defined on the table. As result we avoid using update-on-the-fly method in cases when trigger updates part of key which is used by select which filters rows to be updated and thus avoid infinite updates. By doing such check here we cover both UPDATE and MULTI-UPDATE cases. sql/mysql_priv.h: Renamed check_if_key_used() to is_key_used(). sql/opt_range.cc: Renamed check_if_key_used()/QUICK_SELECT_I::check_if_keys_used() to is_key_used()/QUICK_SELECT_I::is_keys_used(). sql/opt_range.h: Renamed QUICK_SELECT_I::check_if_keys_used() method to is_keys_used(), also updated comment describing it to reflect its extended semantics (this change was caused by change in check_if_key_used()/is_key_used() routine semantics). sql/sql_trigger.cc: Introduced Table_triggers_list::is_updated_in_before_update_triggers() method which is needed for checking if field of subject table can be changed in before update trigger. sql/sql_trigger.h: Table_triggers_list: Removed has_before_update_triggers() method which is not used any longer. Added declaration of is_updated_in_before_update_triggers() which is needed for checking if field of subject table can be changed by before update trigger. sql/sql_update.cc: safe_update_on_fly(): check_if_key_used() routine and check_if_keys_used() method were renamed to is_key_used()/is_keys_used(). Now cases when trigger updates fields which are part of key used for filtering rows for update are caught directly in is_key_used(). This also allows to cover both UPDATE and MULTI-UPDATE cases.
Diffstat (limited to 'sql/key.cc')
-rw-r--r--sql/key.cc24
1 files changed, 20 insertions, 4 deletions
diff --git a/sql/key.cc b/sql/key.cc
index 75161e4f616..5e658312352 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -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
@@ -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+
@@ -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;
}
/*
@@ -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;
}