1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Fix for bugs:

#5860 "Multi-table UPDATE does not activate update triggers"
 #6812 "Triggers are not activated for INSERT ... SELECT"
 #8755 "Trigger is not activated by LOAD DATA".
This patch also implements proper handling of triggers for special forms
of insert like REPLACE or INSERT ... ON DUPLICATE KEY UPDATE. 
Also now we don't call after trigger in case when we have failed to
inserted/update or delete row. Trigger failure should stop statement
execution.

I have not properly tested handling of errors which happen inside of
triggers in this patch, since it is simplier to do this once we will be
able to access tables from triggers.
This commit is contained in:
dlenev@brandersnatch.localdomain
2005-05-24 22:19:33 +04:00
parent 187ee4712b
commit 007a205918
12 changed files with 634 additions and 127 deletions

View File

@@ -398,14 +398,13 @@ int mysql_update(THD *thd,
if (!(select && select->skip_record()))
{
store_record(table,record[1]);
if (fill_record(thd, fields, values, 0))
if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
table->triggers,
TRG_EVENT_UPDATE))
break; /* purecov: inspected */
found++;
if (table->triggers)
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_BEFORE);
if (compare_record(table, query_id))
{
if ((res= table_list->view_check_option(thd, ignore)) !=
@@ -425,6 +424,14 @@ int mysql_update(THD *thd,
{
updated++;
thd->no_trans_update= !transactional_table;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
{
error= 1;
break;
}
}
else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
{
@@ -435,9 +442,6 @@ int mysql_update(THD *thd,
}
}
if (table->triggers)
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER);
if (!--limit && using_limit)
{
error= -1; // Simulate end of file
@@ -1073,8 +1077,8 @@ multi_update::initialize_tables(JOIN *join)
NOTES
We can update the first table in join on the fly if we know that
a row in this tabel will never be read twice. This is true under
the folloing conditions:
a row in this table will never be read twice. This is true under
the following conditions:
- We are doing a table scan and the data is in a separate file (MyISAM) or
if we don't update a clustered key.
@@ -1082,6 +1086,10 @@ multi_update::initialize_tables(JOIN *join)
- We are doing a range scan and we don't update the scan key or
the primary key for a clustered table handler.
When checking for above cases we also should take into account that
BEFORE UPDATE trigger potentially may change value of any field in row
being updated.
WARNING
This code is a bit dependent of how make_join_readinfo() works.
@@ -1099,15 +1107,21 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case JT_EQ_REF:
return TRUE; // At most one matching row
case JT_REF:
return !check_if_key_used(table, join_tab->ref.key, *fields);
return !check_if_key_used(table, join_tab->ref.key, *fields) &&
!(table->triggers &&
table->triggers->has_before_update_triggers());
case JT_ALL:
/* If range search on index */
if (join_tab->quick)
return !join_tab->quick->check_if_keys_used(fields);
return !join_tab->quick->check_if_keys_used(fields) &&
!(table->triggers &&
table->triggers->has_before_update_triggers());
/* If scanning in clustered key */
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key < MAX_KEY)
return !check_if_key_used(table, table->s->primary_key, *fields);
return !check_if_key_used(table, table->s->primary_key, *fields) &&
!(table->triggers &&
table->triggers->has_before_update_triggers());
return TRUE;
default:
break; // Avoid compler warning
@@ -1170,8 +1184,10 @@ bool multi_update::send_data(List<Item> &not_used_values)
{
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
if (fill_record(thd, *fields_for_table[offset],
*values_for_table[offset], 0))
if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
*values_for_table[offset], 0,
table->triggers,
TRG_EVENT_UPDATE))
DBUG_RETURN(1);
found++;
@@ -1207,8 +1223,15 @@ bool multi_update::send_data(List<Item> &not_used_values)
DBUG_RETURN(1);
}
}
else if (!table->file->has_transactions())
thd->no_trans_update= 1;
else
{
if (!table->file->has_transactions())
thd->no_trans_update= 1;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
DBUG_RETURN(1);
}
}
}
else
@@ -1329,6 +1352,11 @@ int multi_update::do_updates(bool from_send_error)
copy_field_ptr++)
(*copy_field_ptr->do_copy)(copy_field_ptr);
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_BEFORE, TRUE))
goto err2;
if (compare_record(table, thd->query_id))
{
if ((local_error=table->file->update_row(table->record[1],
@@ -1338,6 +1366,11 @@ int multi_update::do_updates(bool from_send_error)
goto err;
}
updated++;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
goto err2;
}
}
@@ -1360,6 +1393,7 @@ err:
table->file->print_error(local_error,MYF(0));
}
err2:
(void) table->file->ha_rnd_end();
(void) tmp_table->file->ha_rnd_end();