From 007a20591892beb3734ed4d29fdfe28b750f435a Mon Sep 17 00:00:00 2001 From: "dlenev@brandersnatch.localdomain" <> Date: Tue, 24 May 2005 22:19:33 +0400 Subject: 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. --- sql/sql_trigger.h | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'sql/sql_trigger.h') diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 90c906fc72f..d61da8ff06b 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -8,10 +8,20 @@ class Table_triggers_list: public Sql_alloc /* Triggers as SPs grouped by event, action_time */ sp_head *bodies[3][2]; /* - Copy of TABLE::Field array with field pointers set to old version - of record, used for OLD values in trigger on UPDATE. + Copy of TABLE::Field array with field pointers set to TABLE::record[1] + buffer instead of TABLE::record[0] (used for OLD values in on UPDATE + trigger and DELETE trigger when it is called for REPLACE). */ + Field **record1_field; + /* + During execution of trigger new_field and old_field should point to the + array of fields representing new or old version of row correspondingly + (so it can point to TABLE::field or to Tale_triggers_list::record1_field) + */ + Field **new_field; Field **old_field; + /* TABLE instance for which this triggers list object was created */ + TABLE *table; /* Names of triggers. Should correspond to order of triggers on definitions_list, @@ -26,8 +36,8 @@ public: */ List definitions_list; - Table_triggers_list(): - old_field(0) + Table_triggers_list(TABLE *table_arg): + record1_field(0), table(table_arg) { bzero((char *)bodies, sizeof(bodies)); } @@ -36,7 +46,8 @@ public: bool create_trigger(THD *thd, TABLE_LIST *table); bool drop_trigger(THD *thd, TABLE_LIST *table); bool process_triggers(THD *thd, trg_event_type event, - trg_action_time_type time_type) + trg_action_time_type time_type, + bool old_row_is_record1) { int res= 0; @@ -48,6 +59,17 @@ public: thd->net.no_send_ok= TRUE; #endif + if (old_row_is_record1) + { + old_field= record1_field; + new_field= table->field; + } + else + { + new_field= record1_field; + old_field= table->field; + } + /* FIXME: We should juggle with security context here (because trigger should be invoked with creator rights). @@ -79,8 +101,13 @@ public: bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]); } + bool has_before_update_triggers() + { + return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); + } + friend class Item_trigger_field; private: - bool prepare_old_row_accessors(TABLE *table); + bool prepare_record1_accessors(TABLE *table); }; -- cgit v1.2.1