summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/ddl_log.cc12
-rw-r--r--sql/sql_rename.cc16
-rw-r--r--sql/sql_table.cc32
-rw-r--r--sql/sql_trigger.cc145
-rw-r--r--sql/sql_trigger.h34
5 files changed, 176 insertions, 63 deletions
diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc
index 7eae243771b..5f9a025c042 100644
--- a/sql/ddl_log.cc
+++ b/sql/ddl_log.cc
@@ -1160,6 +1160,7 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
case DDL_RENAME_PHASE_TRIGGER:
{
MDL_request mdl_request;
+ TRIGGER_RENAME_PARAM trigger_param;
build_filename_and_delete_tmp_file(to_path, sizeof(to_path),
&ddl_log_entry->db,
@@ -1195,14 +1196,20 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
error= thd->mdl_context.acquire_lock(&mdl_request, 1);
/* acquire_locks() should never fail during recovery */
DBUG_ASSERT(error == 0);
-
+ (void) Table_triggers_list::prepare_for_rename(thd,
+ &trigger_param,
+ &ddl_log_entry->db,
+ &to_table,
+ &to_converted_name,
+ &ddl_log_entry->from_db,
+ &from_table);
(void) Table_triggers_list::change_table_name(thd,
+ &trigger_param,
&ddl_log_entry->db,
&to_table,
&to_converted_name,
&ddl_log_entry->from_db,
&from_table);
-
thd->mdl_context.release_lock(mdl_request.ticket);
}
if (ddl_log_increment_phase_no_lock(entry_pos))
@@ -1726,7 +1733,6 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
}
break;
}
- }
default:
DBUG_ASSERT(0);
break;
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 2b2f32cf126..ec782792f30 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2013, Monty Program Ab.
+ Copyright (c) 2011, 2021, Monty Program 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
@@ -339,6 +339,7 @@ do_rename(THD *thd, rename_param *param, DDL_LOG_STATE *ddl_log_state,
int rc= 1;
handlerton *hton;
LEX_CSTRING *old_alias, *new_alias;
+ TRIGGER_RENAME_PARAM rename_param;
DBUG_ENTER("do_rename");
DBUG_PRINT("enter", ("skip_error: %d", (int) skip_error));
@@ -361,6 +362,15 @@ do_rename(THD *thd, rename_param *param, DDL_LOG_STATE *ddl_log_state,
if (hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
*force_if_exists= 1;
+ /* Check if we can rename triggers */
+ if (Table_triggers_list::prepare_for_rename(thd, &rename_param,
+ &ren_table->db,
+ old_alias,
+ &ren_table->table_name,
+ new_db,
+ new_alias))
+ DBUG_RETURN(!skip_error);
+
thd->replication_flags= 0;
if (ddl_log_rename_table(thd, ddl_log_state, hton,
@@ -379,7 +389,9 @@ do_rename(THD *thd, rename_param *param, DDL_LOG_STATE *ddl_log_state,
debug_crash_here("ddl_log_rename_before_rename_trigger");
- if (!(rc= Table_triggers_list::change_table_name(thd, &ren_table->db,
+ if (!(rc= Table_triggers_list::change_table_name(thd,
+ &rename_param,
+ &ren_table->db,
old_alias,
&ren_table->table_name,
new_db,
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f00aaaee00a..7b3b0eb1136 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -7058,6 +7058,7 @@ static bool mysql_inplace_alter_table(THD *thd,
TABLE *altered_table,
Alter_inplace_info *ha_alter_info,
MDL_request *target_mdl_request,
+ TRIGGER_RENAME_PARAM *trigger_param,
Alter_table_ctx *alter_ctx)
{
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN | MYSQL_OPEN_IGNORE_KILLED);
@@ -7330,7 +7331,7 @@ static bool mysql_inplace_alter_table(THD *thd,
*/
DBUG_RETURN(true);
}
- if (Table_triggers_list::change_table_name(thd,
+ if (Table_triggers_list::change_table_name(thd, trigger_param,
&alter_ctx->db,
&alter_ctx->alias,
&alter_ctx->table_name,
@@ -7343,7 +7344,8 @@ static bool mysql_inplace_alter_table(THD *thd,
*/
(void) mysql_rename_table(db_type,
&alter_ctx->new_db, &alter_ctx->new_alias,
- &alter_ctx->db, &alter_ctx->alias, NO_FK_CHECKS);
+ &alter_ctx->db, &alter_ctx->alias,
+ NO_FK_CHECKS);
DBUG_RETURN(true);
}
rename_table_in_stat_tables(thd, &alter_ctx->db, &alter_ctx->alias,
@@ -8849,6 +8851,7 @@ simple_tmp_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
static bool
simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
Alter_info::enum_enable_or_disable keys_onoff,
+ TRIGGER_RENAME_PARAM *trigger_param,
Alter_table_ctx *alter_ctx)
{
TABLE *table= table_list->table;
@@ -8895,7 +8898,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
if (mysql_rename_table(old_db_type, &alter_ctx->db, &alter_ctx->table_name,
&alter_ctx->new_db, &alter_ctx->new_alias, 0))
error= -1;
- else if (Table_triggers_list::change_table_name(thd,
+ else if (Table_triggers_list::change_table_name(thd, trigger_param,
&alter_ctx->db,
&alter_ctx->alias,
&alter_ctx->table_name,
@@ -9080,6 +9083,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
MDL_request target_mdl_request;
MDL_ticket *mdl_ticket= 0;
Alter_table_prelocking_strategy alter_prelocking_strategy;
+ TRIGGER_RENAME_PARAM trigger_param;
DBUG_ENTER("mysql_alter_table");
/*
@@ -9504,6 +9508,16 @@ do_continue:;
create_info))
DBUG_RETURN(true);
+ /* Check if rename of triggers are supported */
+ if (alter_ctx.is_table_renamed() &&
+ Table_triggers_list::prepare_for_rename(thd, &trigger_param,
+ &alter_ctx.db,
+ &alter_ctx.alias,
+ &alter_ctx.table_name,
+ &alter_ctx.new_db,
+ &alter_ctx.new_alias))
+ DBUG_RETURN(true);
+
/*
Look if we have to do anything at all.
ALTER can become NOOP after handling
@@ -9549,6 +9563,7 @@ do_continue:;
}
res= simple_rename_or_index_change(thd, table_list,
alter_info->keys_onoff,
+ &trigger_param,
&alter_ctx);
}
else
@@ -9805,7 +9820,7 @@ do_continue:;
&altered_table))
goto err_new_table_cleanup;
/*
- Avoid creating frm again in ha_create_table() if inline alter will not
+ Avoid creating frm again in ha_create_table() if inplace alter will not
be used.
*/
frm_is_created= 1;
@@ -9879,9 +9894,12 @@ do_continue:;
*/
enum_check_fields org_count_cuted_fields= thd->count_cuted_fields;
thd->count_cuted_fields= CHECK_FIELD_WARN;
- int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table,
+ int res= mysql_inplace_alter_table(thd,
+ table_list, table, &altered_table,
&ha_alter_info,
- &target_mdl_request, &alter_ctx);
+ &target_mdl_request,
+ &trigger_param,
+ &alter_ctx);
thd->count_cuted_fields= org_count_cuted_fields;
my_free(const_cast<uchar*>(frm.str));
@@ -10216,7 +10234,7 @@ do_continue:;
// Check if we renamed the table and if so update trigger files.
if (alter_ctx.is_table_renamed())
{
- if (Table_triggers_list::change_table_name(thd,
+ if (Table_triggers_list::change_table_name(thd, &trigger_param,
&alter_ctx.db,
&alter_ctx.alias,
&alter_ctx.table_name,
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index e3149799b6e..181cca39f7e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -45,6 +45,18 @@ static bool add_table_for_trigger_internal(THD *thd,
TABLE_LIST **table,
char *trn_path_buff);
+/*
+ Functions for TRIGGER_RENAME_PARAM
+*/
+
+void TRIGGER_RENAME_PARAM::reset()
+{
+ delete table.triggers;
+ table.triggers= 0;
+ free_root(&table.mem_root, MYF(0));
+}
+
+
/**
Trigger_creation_ctx -- creation context of triggers.
*/
@@ -2206,64 +2218,43 @@ bool Trigger::change_on_table_name(void* param_arg)
}
-/**
- Update .TRG and .TRN files after renaming triggers' subject table.
-
- @param[in,out] thd Thread context
- @param[in] db Old database of subject table
- @param[in] old_alias Old alias of subject table
- @param[in] old_table Old name of subject table. The difference between
- old_table and old_alias is that in case of lower_case_table_names
- old_table == lowercase(old_alias)
- @param[in] new_db New database for subject table
- @param[in] 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.
- Also this method assumes that subject table is not renamed to itself.
- This method needs to be called under an exclusive table metadata lock.
+/*
+ Check if we can rename triggers in change_table_name()
+ The idea is to ensure that it is close to impossible that
+ change_table_name() should fail.
- @retval FALSE Success
- @retval TRUE Error
+ @return 0 ok
+ @return 1 Error: rename of triggers would fail
*/
-bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
- const LEX_CSTRING *old_alias,
- const LEX_CSTRING *old_table,
- const LEX_CSTRING *new_db,
- const LEX_CSTRING *new_table)
+bool
+Table_triggers_list::prepare_for_rename(THD *thd,
+ TRIGGER_RENAME_PARAM *param,
+ const LEX_CSTRING *db,
+ const LEX_CSTRING *old_alias,
+ const LEX_CSTRING *old_table,
+ const LEX_CSTRING *new_db,
+ const LEX_CSTRING *new_table)
{
- TABLE table;
+ TABLE *table= &param->table;
bool result= 0;
- bool upgrading50to51= FALSE;
- Trigger *err_trigger;
- DBUG_ENTER("Triggers::change_table_name");
+ DBUG_ENTER("Table_triggers_lists::prepare_change_table_name");
- table.reset();
init_sql_alloc(key_memory_Table_trigger_dispatcher,
- &table.mem_root, 8192, 0, MYF(0));
-
- /*
- This method interfaces the mysql server code protected by
- an exclusive metadata lock.
- */
- DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db->str,
- old_table->str,
- MDL_EXCLUSIVE));
+ &table->mem_root, 8192, 0, MYF(0));
DBUG_ASSERT(my_strcasecmp(table_alias_charset, db->str, new_db->str) ||
- my_strcasecmp(table_alias_charset, old_alias->str, new_table->str));
+ my_strcasecmp(table_alias_charset, old_alias->str,
+ new_table->str));
- if (Table_triggers_list::check_n_load(thd, db, old_table, &table, TRUE))
+ if (Table_triggers_list::check_n_load(thd, db, old_table, table, TRUE))
{
result= 1;
goto end;
}
- if (table.triggers)
+ if (table->triggers)
{
- if (table.triggers->check_for_broken_triggers())
+ if (table->triggers->check_for_broken_triggers())
{
result= 1;
goto end;
@@ -2284,7 +2275,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
if (check_n_cut_mysql50_prefix(db->str, dbname, sizeof(dbname)) &&
!my_strcasecmp(table_alias_charset, dbname, new_db->str))
{
- upgrading50to51= TRUE;
+ param->upgrading50to51= TRUE;
}
else
{
@@ -2293,14 +2284,70 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
goto end;
}
}
- if (unlikely(table.triggers->change_table_name_in_triggers(thd, db, new_db,
+ }
+
+end:
+ param->got_error= result;
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Update .TRG and .TRN files after renaming triggers' subject table.
+
+ @param[in,out] thd Thread context
+ @param[in] db Old database of subject table
+ @param[in] old_alias Old alias of subject table
+ @param[in] old_table Old name of subject table. The difference between
+ old_table and old_alias is that in case of lower_case_table_names
+ old_table == lowercase(old_alias)
+ @param[in] new_db New database for subject table
+ @param[in] 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.
+ Also this method assumes that subject table is not renamed to itself.
+ This method needs to be called under an exclusive table metadata lock.
+
+ @retval FALSE Success
+ @retval TRUE Error
+*/
+
+bool Table_triggers_list::change_table_name(THD *thd,
+ TRIGGER_RENAME_PARAM *param,
+ const LEX_CSTRING *db,
+ const LEX_CSTRING *old_alias,
+ const LEX_CSTRING *old_table,
+ const LEX_CSTRING *new_db,
+ const LEX_CSTRING *new_table)
+{
+ TABLE *table= &param->table;
+ bool result= 0;
+ bool upgrading50to51= FALSE;
+ Trigger *err_trigger;
+ DBUG_ENTER("Table_triggers_list::change_table_name");
+
+ DBUG_ASSERT(!param->got_error);
+ /*
+ This method interfaces the mysql server code protected by
+ an exclusive metadata lock.
+ */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db->str,
+ old_table->str,
+ MDL_EXCLUSIVE));
+
+ if (table->triggers)
+ {
+ if (unlikely(table->triggers->change_table_name_in_triggers(thd, db, new_db,
old_alias,
new_table)))
{
result= 1;
goto end;
}
- if ((err_trigger= table.triggers->
+ if ((err_trigger= table->triggers->
change_table_name_in_trignames( upgrading50to51 ? db : NULL,
new_db, new_table, 0)))
{
@@ -2310,10 +2357,10 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
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(
+ (void) table->triggers->change_table_name_in_trignames(
upgrading50to51 ? new_db : NULL, db,
old_alias, err_trigger);
- (void) table.triggers->change_table_name_in_triggers(
+ (void) table->triggers->change_table_name_in_triggers(
thd, db, new_db,
new_table, old_alias);
result= 1;
@@ -2322,8 +2369,6 @@ bool Table_triggers_list::change_table_name(THD *thd, const LEX_CSTRING *db,
}
end:
- delete table.triggers;
- free_root(&table.mem_root, MYF(0));
DBUG_RETURN(result);
}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 98e527a50c0..739669c86a5 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -79,6 +79,30 @@ struct st_trg_execution_order
};
+/*
+ Parameter to change_table_name_in_triggers()
+*/
+
+class TRIGGER_RENAME_PARAM
+{
+public:
+ TABLE table;
+ bool upgrading50to51;
+ bool got_error;
+
+ TRIGGER_RENAME_PARAM()
+ {
+ upgrading50to51= got_error= 0;
+ table.reset();
+ }
+ ~TRIGGER_RENAME_PARAM()
+ {
+ reset();
+ }
+ void reset();
+};
+
+
class Table_triggers_list;
/**
@@ -237,7 +261,14 @@ public:
TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, const LEX_CSTRING *db,
const LEX_CSTRING *table_name, myf MyFlags);
- static bool change_table_name(THD *thd, const LEX_CSTRING *db,
+ static bool prepare_for_rename(THD *thd, TRIGGER_RENAME_PARAM *param,
+ const LEX_CSTRING *db,
+ const LEX_CSTRING *old_alias,
+ const LEX_CSTRING *old_table,
+ const LEX_CSTRING *new_db,
+ const LEX_CSTRING *new_table);
+ static bool change_table_name(THD *thd, TRIGGER_RENAME_PARAM *param,
+ const LEX_CSTRING *db,
const LEX_CSTRING *old_alias,
const LEX_CSTRING *old_table,
const LEX_CSTRING *new_db,
@@ -315,6 +346,7 @@ private:
}
};
+
bool add_table_for_trigger(THD *thd,
const sp_name *trg_name,
bool continue_if_not_exist,