summaryrefslogtreecommitdiff
path: root/sql/sql_trigger.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_trigger.cc')
-rw-r--r--sql/sql_trigger.cc286
1 files changed, 266 insertions, 20 deletions
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 0198dba780d..e33dc52df8f 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -65,7 +65,6 @@ File_option sql_modes_parameters=
*/
static const int TRG_NUM_REQUIRED_PARAMETERS= 4;
-static const int TRG_MAX_VERSIONS= 3;
/*
Structure representing contents of .TRN file which are used to support
@@ -318,8 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
- trigname_path[FN_REFLEN];
+ char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
LEX_STRING file, trigname_file;
LEX_STRING *trg_def, *name;
ulonglong *trg_sql_mode;
@@ -472,12 +470,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
definer_host->str, NullS) - trg_definer->str;
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
- (gptr)this, triggers_file_parameters,
- TRG_MAX_VERSIONS))
+ (gptr)this, triggers_file_parameters, 0))
return 0;
err_with_cleanup:
- my_delete(trigname_path, MYF(MY_WME));
+ my_delete(trigname_buff, MYF(MY_WME));
return 1;
}
@@ -497,7 +494,8 @@ err_with_cleanup:
True - error
*/
-static bool rm_trigger_file(char *path, char *db, char *table_name)
+static bool rm_trigger_file(char *path, const char *db,
+ const char *table_name)
{
build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext);
return my_delete(path, MYF(MY_WME));
@@ -519,7 +517,8 @@ static bool rm_trigger_file(char *path, char *db, char *table_name)
True - error
*/
-static bool rm_trigname_file(char *path, char *db, char *trigger_name)
+static bool rm_trigname_file(char *path, const char *db,
+ const char *trigger_name)
{
build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext);
return my_delete(path, MYF(MY_WME));
@@ -527,6 +526,35 @@ static bool rm_trigname_file(char *path, char *db, char *trigger_name)
/*
+ Helper function that saves .TRG file for Table_triggers_list object.
+
+ SYNOPSIS
+ save_trigger_file()
+ triggers Table_triggers_list object for which file should be saved
+ db Name of database for subject table
+ table_name Name of subject table
+
+ RETURN VALUE
+ FALSE Success
+ TRUE Error
+*/
+
+static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
+ const char *table_name)
+{
+ char file_buff[FN_REFLEN];
+ LEX_STRING file;
+
+ file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
+ triggers_file_ext);
+ file.str= file_buff;
+ return sql_create_definition_file(NULL, &file, &triggers_file_type,
+ (gptr)triggers, triggers_file_parameters,
+ 0);
+}
+
+
+/*
Drop trigger for table.
SYNOPSIS
@@ -579,16 +607,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
}
else
{
- char file_buff[FN_REFLEN];
- LEX_STRING file;
-
- file.length= build_table_filename(file_buff, FN_REFLEN-1,
- tables->db, tables->table_name,
- triggers_file_ext);
- file.str= file_buff;
- if (sql_create_definition_file(NULL, &file, &triggers_file_type,
- (gptr)this, triggers_file_parameters,
- TRG_MAX_VERSIONS))
+ if (save_trigger_file(this, tables->db, tables->table_name))
return 1;
}
@@ -827,12 +846,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
if (!names_only && triggers->prepare_record1_accessors(table))
DBUG_RETURN(1);
- char *trg_name_buff;
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
LEX *old_lex= thd->lex, lex;
sp_rcontext *save_spcont= thd->spcont;
ulong save_sql_mode= thd->variables.sql_mode;
+ LEX_STRING *on_table_name;
thd->lex= &lex;
@@ -898,6 +917,21 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
&table->mem_root))
goto err_with_lex_cleanup;
+ if (!(on_table_name= (LEX_STRING*) alloc_root(&table->mem_root,
+ sizeof(LEX_STRING))))
+ goto err_with_lex_cleanup;
+ *on_table_name= lex.ident;
+ if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root))
+ goto err_with_lex_cleanup;
+
+ /*
+ Let us check that we correctly update trigger definitions when we
+ rename tables with triggers.
+ */
+ DBUG_ASSERT(!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) &&
+ !my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
+ table_name));
+
if (names_only)
{
lex_end(&lex);
@@ -1063,7 +1097,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
- trigname.trigger_table.str, TL_WRITE));
+ trigname.trigger_table.str, TL_IGNORE));
}
@@ -1133,6 +1167,218 @@ end:
}
+/*
+ Update .TRG file after renaming triggers' subject table
+ (change name of table in triggers' definitions).
+
+ SYNOPSIS
+ change_table_name_in_triggers()
+ thd Thread context
+ db_name Database of subject table
+ old_table_name Old subject table's name
+ new_table_name New subject table's name
+
+ RETURN VALUE
+ FALSE Success
+ TRUE Failure
+*/
+
+bool
+Table_triggers_list::change_table_name_in_triggers(THD *thd,
+ const char *db_name,
+ LEX_STRING *old_table_name,
+ LEX_STRING *new_table_name)
+{
+ char path_buff[FN_REFLEN];
+ LEX_STRING *def, *on_table_name, new_def;
+ ulonglong *sql_mode;
+ ulong save_sql_mode= thd->variables.sql_mode;
+ List_iterator_fast<LEX_STRING> it_def(definitions_list);
+ List_iterator_fast<LEX_STRING> it_on_table_name(on_table_names_list);
+ List_iterator_fast<ulonglong> it_mode(definition_modes_list);
+ uint on_q_table_name_len, before_on_len;
+ String buff;
+
+ DBUG_ASSERT(definitions_list.elements == on_table_names_list.elements &&
+ definitions_list.elements == definition_modes_list.elements);
+
+ while ((def= it_def++))
+ {
+ on_table_name= it_on_table_name++;
+ thd->variables.sql_mode= *(it_mode++);
+
+ /* Construct CREATE TRIGGER statement with new table name. */
+ buff.length(0);
+ before_on_len= on_table_name->str - def->str;
+ buff.append(def->str, before_on_len);
+ buff.append(STRING_WITH_LEN("ON "));
+ append_identifier(thd, &buff, new_table_name->str, new_table_name->length);
+ on_q_table_name_len= buff.length() - before_on_len;
+ buff.append(on_table_name->str + on_table_name->length,
+ def->length - (before_on_len + on_table_name->length));
+ /*
+ It is OK to allocate some memory on table's MEM_ROOT since this
+ table instance will be thrown out at the end of rename anyway.
+ */
+ new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
+ new_def.length= buff.length();
+ on_table_name->str= new_def.str + before_on_len;
+ on_table_name->length= on_q_table_name_len;
+ *def= new_def;
+ }
+
+ thd->variables.sql_mode= save_sql_mode;
+
+ if (thd->is_fatal_error)
+ return TRUE; /* OOM */
+
+ if (save_trigger_file(this, db_name, new_table_name->str))
+ return TRUE;
+ if (rm_trigger_file(path_buff, db_name, old_table_name->str))
+ {
+ (void) rm_trigger_file(path_buff, db_name, new_table_name->str);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ Iterate though Table_triggers_list::names_list list and update .TRN files
+ after renaming triggers' subject table.
+
+ SYNOPSIS
+ change_table_name_in_trignames()
+ db_name Database of subject table
+ new_table_name New subject table's name
+ stopper Pointer to Table_triggers_list::names_list at
+ which we should stop updating.
+
+ RETURN VALUE
+ 0 Success
+ non-0 Failure, pointer to Table_triggers_list::names_list element
+ for which update failed.
+*/
+
+LEX_STRING*
+Table_triggers_list::change_table_name_in_trignames(const char *db_name,
+ LEX_STRING *new_table_name,
+ LEX_STRING *stopper)
+{
+ char trigname_buff[FN_REFLEN];
+ struct st_trigname trigname;
+ LEX_STRING trigname_file;
+ LEX_STRING *trigger;
+ List_iterator_fast<LEX_STRING> it_name(names_list);
+
+ while ((trigger= it_name++) != stopper)
+ {
+ trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
+ db_name, trigger->str,
+ trigname_file_ext);
+ trigname_file.str= trigname_buff;
+
+ trigname.trigger_table= *new_table_name;
+
+ if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
+ (gptr)&trigname, trigname_file_parameters,
+ 0))
+ return trigger;
+ }
+
+ return 0;
+}
+
+
+/*
+ Update .TRG and .TRN files after renaming triggers' subject table.
+
+ SYNOPSIS
+ change_table_name()
+ thd Thread context
+ db Old database of subject table
+ old_table Old name of subject table
+ new_db New database for subject table
+ new_table New name of subject table
+
+ NOTE
+ This method tries to leave trigger related files in consistent state,
+ i.e. it either will complete successfully, or will fail leaving files
+ in their initial state.
+
+ RETURN VALUE
+ FALSE Success
+ TRUE Error
+*/
+
+bool Table_triggers_list::change_table_name(THD *thd, const char *db,
+ const char *old_table,
+ const char *new_db,
+ const char *new_table)
+{
+ TABLE table;
+ bool result= 0;
+ LEX_STRING *err_trigname;
+ DBUG_ENTER("change_table_name");
+
+ bzero(&table, sizeof(table));
+ init_alloc_root(&table.mem_root, 8192, 0);
+
+ safe_mutex_assert_owner(&LOCK_open);
+
+ if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
+ {
+ result= 1;
+ goto end;
+ }
+ if (table.triggers)
+ {
+ LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
+ LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+ /*
+ Since triggers should be in the same schema as their subject tables
+ moving table with them between two schemas raises too many questions.
+ (E.g. what should happen if in new schema we already have trigger
+ with same name ?).
+ */
+ if (my_strcasecmp(table_alias_charset, db, new_db))
+ {
+ my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
+ result= 1;
+ goto end;
+ }
+ if (table.triggers->change_table_name_in_triggers(thd, db,
+ &old_table_name,
+ &new_table_name))
+ {
+ result= 1;
+ goto end;
+ }
+ if ((err_trigname= table.triggers->change_table_name_in_trignames(
+ db, &new_table_name, 0)))
+ {
+ /*
+ If we were unable to update one of .TRN files properly we will
+ revert all changes that we have done and report about error.
+ We assume that we will be able to undo our changes without errors
+ (we can't do much if there will be an error anyway).
+ */
+ (void) table.triggers->change_table_name_in_trignames(db,
+ &old_table_name,
+ err_trigname);
+ (void) table.triggers->change_table_name_in_triggers(thd, db,
+ &new_table_name,
+ &old_table_name);
+ result= 1;
+ goto end;
+ }
+ }
+end:
+ delete table.triggers;
+ free_root(&table.mem_root, MYF(0));
+ DBUG_RETURN(result);
+}
+
bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
trg_action_time_type time_type,