mariadb/sql/sql_trigger.h

142 lines
5.3 KiB
C
Raw Normal View History

/* Copyright (C) 2004-2005 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
This class holds all information about triggers of table.
QQ: Will it be merged into TABLE in future ?
*/
class Table_triggers_list: public Sql_alloc
{
/* Triggers as SPs grouped by event, action_time */
sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
Fix for bug#18437 "Wrong values inserted with a before update trigger on NDB table". SQL-layer was not marking fields which were used in triggers as such. As result these fields were not always properly retrieved/stored by handler layer. So one might got wrong values or lost changes in triggers for NDB, Federated and possibly InnoDB tables. This fix solves the problem by marking fields used in triggers appropriately. Also this patch contains the following cleanup of ha_ndbcluster code: We no longer rely on reading LEX::sql_command value in handler in order to determine if we can enable optimization which allows us to handle REPLACE statement in more efficient way by doing replaces directly in write_row() method without reporting error to SQL-layer. Instead we rely on SQL-layer informing us whether this optimization applicable by calling handler::extra() method with HA_EXTRA_WRITE_CAN_REPLACE flag. As result we no longer apply this optimzation in cases when it should not be used (e.g. if we have on delete triggers on table) and use in some additional cases when it is applicable (e.g. for LOAD DATA REPLACE). Finally this patch includes fix for bug#20728 "REPLACE does not work correctly for NDB table with PK and unique index". This was yet another problem which was caused by improper field mark-up. During row replacement fields which weren't explicity used in REPLACE statement were not marked as fields to be saved (updated) so they have retained values from old row version. The fix is to mark all table fields as set for REPLACE statement. Note that in 5.1 we already solve this problem by notifying handler that it should save values from all fields only in case when real replacement happens.
2006-07-01 23:51:10 +02:00
/*
Heads of the lists linking items for all fields used in triggers
grouped by event and action_time.
*/
Item_trigger_field *trigger_fields[TRG_EVENT_MAX][TRG_ACTION_MAX];
/*
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,
used in CREATE/DROP TRIGGER for looking up trigger by name.
*/
List<LEX_STRING> names_list;
/*
List of "ON table_name" parts in trigger definitions, used for
updating trigger definitions during RENAME TABLE.
*/
List<LEX_STRING> on_table_names_list;
/*
Key representing triggers for this table in set of all stored
routines used by statement.
TODO: We won't need this member once triggers namespace will be
database-wide instead of table-wide because then we will be able
to use key based on sp_name as for other stored routines.
*/
LEX_STRING sroutines_key;
/*
Grant information for each trigger (pair: subject table, trigger definer).
*/
GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX];
public:
/*
Field responsible for storing triggers definitions in file.
It have to be public because we are using it directly from parser.
*/
List<LEX_STRING> definitions_list;
/*
List of sql modes for triggers
*/
List<ulonglong> definition_modes_list;
List<LEX_STRING> definers_list;
Table_triggers_list(TABLE *table_arg):
record1_field(0), table(table_arg)
{
bzero((char *)bodies, sizeof(bodies));
Fix for bug#18437 "Wrong values inserted with a before update trigger on NDB table". SQL-layer was not marking fields which were used in triggers as such. As result these fields were not always properly retrieved/stored by handler layer. So one might got wrong values or lost changes in triggers for NDB, Federated and possibly InnoDB tables. This fix solves the problem by marking fields used in triggers appropriately. Also this patch contains the following cleanup of ha_ndbcluster code: We no longer rely on reading LEX::sql_command value in handler in order to determine if we can enable optimization which allows us to handle REPLACE statement in more efficient way by doing replaces directly in write_row() method without reporting error to SQL-layer. Instead we rely on SQL-layer informing us whether this optimization applicable by calling handler::extra() method with HA_EXTRA_WRITE_CAN_REPLACE flag. As result we no longer apply this optimzation in cases when it should not be used (e.g. if we have on delete triggers on table) and use in some additional cases when it is applicable (e.g. for LOAD DATA REPLACE). Finally this patch includes fix for bug#20728 "REPLACE does not work correctly for NDB table with PK and unique index". This was yet another problem which was caused by improper field mark-up. During row replacement fields which weren't explicity used in REPLACE statement were not marked as fields to be saved (updated) so they have retained values from old row version. The fix is to mark all table fields as set for REPLACE statement. Note that in 5.1 we already solve this problem by notifying handler that it should save values from all fields only in case when real replacement happens.
2006-07-01 23:51:10 +02:00
bzero((char *)trigger_fields, sizeof(trigger_fields));
bzero((char *)&subject_table_grants, sizeof(subject_table_grants));
}
~Table_triggers_list();
bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
bool drop_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
bool process_triggers(THD *thd, trg_event_type event,
trg_action_time_type time_type,
bool old_row_is_record1);
bool get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
LEX_STRING *trigger_name, LEX_STRING *trigger_stmt,
ulong *sql_mode,
LEX_STRING *definer);
static bool check_n_load(THD *thd, const char *db, const char *table_name,
TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
static bool change_table_name(THD *thd, const char *db,
const char *old_table,
const char *new_db,
const char *new_table);
bool has_delete_triggers()
{
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]);
}
void set_table(TABLE *new_table);
Fix for bug#18437 "Wrong values inserted with a before update trigger on NDB table". SQL-layer was not marking fields which were used in triggers as such. As result these fields were not always properly retrieved/stored by handler layer. So one might got wrong values or lost changes in triggers for NDB, Federated and possibly InnoDB tables. This fix solves the problem by marking fields used in triggers appropriately. Also this patch contains the following cleanup of ha_ndbcluster code: We no longer rely on reading LEX::sql_command value in handler in order to determine if we can enable optimization which allows us to handle REPLACE statement in more efficient way by doing replaces directly in write_row() method without reporting error to SQL-layer. Instead we rely on SQL-layer informing us whether this optimization applicable by calling handler::extra() method with HA_EXTRA_WRITE_CAN_REPLACE flag. As result we no longer apply this optimzation in cases when it should not be used (e.g. if we have on delete triggers on table) and use in some additional cases when it is applicable (e.g. for LOAD DATA REPLACE). Finally this patch includes fix for bug#20728 "REPLACE does not work correctly for NDB table with PK and unique index". This was yet another problem which was caused by improper field mark-up. During row replacement fields which weren't explicity used in REPLACE statement were not marked as fields to be saved (updated) so they have retained values from old row version. The fix is to mark all table fields as set for REPLACE statement. Note that in 5.1 we already solve this problem by notifying handler that it should save values from all fields only in case when real replacement happens.
2006-07-01 23:51:10 +02:00
void mark_fields_used(THD *thd, trg_event_type event);
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
2006-09-21 09:35:38 +02:00
bool is_updated_in_before_update_triggers(Field *fld);
friend class Item_trigger_field;
friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
TABLE_LIST *table);
private:
bool prepare_record1_accessors(TABLE *table);
LEX_STRING* change_table_name_in_trignames(const char *db_name,
LEX_STRING *new_table_name,
LEX_STRING *stopper);
bool change_table_name_in_triggers(THD *thd,
const char *db_name,
LEX_STRING *old_table_name,
LEX_STRING *new_table_name);
};
extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];