mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Ensure that one can drop a trigger with an orphan .TRN file
Before this fix, one would get a 'Trigger ... already exists' when trying to create a trigger matching the original name and 'Trigger ... does not exists" when trying to drop it. Fixes a reported bug in MDEV-25180 Atomic ALTER TABLE MDEV-25517 Atomic DDL: Assertion `query_arg' in THD::binlog_query upon DROP TRIGGER The bug was that the stmt_query variable was not populated with the query in case of DROP TRIGGER of an orphan trigger (.TRN file exists & table exists, but the trigger was not in table->triggers).
This commit is contained in:
@ -39,6 +39,12 @@
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static bool add_table_for_trigger_internal(THD *thd,
|
||||
const sp_name *trg_name,
|
||||
bool if_exists,
|
||||
TABLE_LIST **table,
|
||||
char *trn_path_buff);
|
||||
|
||||
/**
|
||||
Trigger_creation_ctx -- creation context of triggers.
|
||||
*/
|
||||
@ -396,6 +402,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
*/
|
||||
TABLE *table;
|
||||
bool result= TRUE;
|
||||
bool add_if_exists_to_binlog= 0, action_executed= 0;
|
||||
String stmt_query;
|
||||
bool lock_upgrade_done= FALSE;
|
||||
bool backup_of_table_list_done= 0;;
|
||||
@ -403,6 +410,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
MDL_request mdl_request_for_trn;
|
||||
Query_tables_list backup;
|
||||
DDL_LOG_STATE ddl_log_state, ddl_log_state_tmp_file;
|
||||
char trn_path_buff[FN_REFLEN];
|
||||
DBUG_ENTER("mysql_create_or_drop_trigger");
|
||||
|
||||
/* Charset of the buffer for statement must be system one. */
|
||||
@ -489,7 +497,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
|
||||
if (add_table_for_trigger_internal(thd, thd->lex->spname, if_exists, &tables,
|
||||
trn_path_buff))
|
||||
goto end;
|
||||
|
||||
if (!tables)
|
||||
@ -505,7 +514,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
*/
|
||||
result= FALSE;
|
||||
/* Still, we need to log the query ... */
|
||||
stmt_query.append(thd->query(), thd->query_length());
|
||||
stmt_query.set(thd->query(), thd->query_length(), system_charset_info);
|
||||
action_executed= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
@ -562,7 +572,15 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
tables->table= open_n_lock_single_table(thd, tables,
|
||||
TL_READ_NO_INSERT, 0);
|
||||
if (! tables->table)
|
||||
{
|
||||
if (!create && thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
|
||||
{
|
||||
/* TRN file exists but table does not. Drop the orphan trigger */
|
||||
thd->clear_error(); // Remove error from open
|
||||
goto drop_orphan_trn;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
tables->table->use_all_columns();
|
||||
}
|
||||
table= tables->table;
|
||||
@ -588,11 +606,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
if (!table->triggers)
|
||||
{
|
||||
if (!create)
|
||||
{
|
||||
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
|
||||
goto end;
|
||||
}
|
||||
|
||||
goto drop_orphan_trn;
|
||||
if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table)))
|
||||
goto end;
|
||||
}
|
||||
@ -618,7 +632,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
&thd->lex->spname->m_name,
|
||||
&stmt_query,
|
||||
&ddl_log_state);
|
||||
if (result)
|
||||
{
|
||||
thd->clear_error(); // Remove error from drop trigger
|
||||
goto drop_orphan_trn;
|
||||
}
|
||||
}
|
||||
action_executed= 1;
|
||||
|
||||
close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
|
||||
|
||||
@ -637,13 +657,19 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
sp_cache_invalidate();
|
||||
|
||||
end:
|
||||
if (!result)
|
||||
if (!result && action_executed)
|
||||
{
|
||||
ulonglong save_option_bits= thd->variables.option_bits;
|
||||
|
||||
debug_crash_here("ddl_log_drop_before_binlog");
|
||||
if (add_if_exists_to_binlog)
|
||||
thd->variables.option_bits|= OPTION_IF_EXISTS;
|
||||
thd->binlog_xid= thd->query_id;
|
||||
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
|
||||
result= write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length());
|
||||
result= write_bin_log(thd, TRUE, stmt_query.ptr(),
|
||||
stmt_query.length());
|
||||
thd->binlog_xid= 0;
|
||||
thd->variables.option_bits= save_option_bits;
|
||||
debug_crash_here("ddl_log_drop_after_binlog");
|
||||
}
|
||||
ddl_log_complete(&ddl_log_state);
|
||||
@ -679,6 +705,16 @@ end:
|
||||
wsrep_error_label:
|
||||
DBUG_RETURN(true);
|
||||
#endif
|
||||
|
||||
drop_orphan_trn:
|
||||
my_error(ER_REMOVED_ORPHAN_TRIGGER, MYF(ME_WARNING),
|
||||
thd->lex->spname->m_name.str, tables->table_name.str);
|
||||
mysql_file_delete(key_file_trg, trn_path_buff, MYF(0));
|
||||
result= thd->is_error();
|
||||
add_if_exists_to_binlog= 1;
|
||||
action_executed= 1; // Ensure query is binlogged
|
||||
stmt_query.set(thd->query(), thd->query_length(), system_charset_info);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
@ -1862,17 +1898,16 @@ void Trigger::get_trigger_info(LEX_CSTRING *trigger_stmt,
|
||||
@retval TRUE Otherwise.
|
||||
*/
|
||||
|
||||
bool add_table_for_trigger(THD *thd,
|
||||
const sp_name *trg_name,
|
||||
bool if_exists,
|
||||
TABLE_LIST **table)
|
||||
static bool add_table_for_trigger_internal(THD *thd,
|
||||
const sp_name *trg_name,
|
||||
bool if_exists,
|
||||
TABLE_LIST **table,
|
||||
char *trn_path_buff)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
char trn_path_buff[FN_REFLEN];
|
||||
LEX_CSTRING trn_path= { trn_path_buff, 0 };
|
||||
LEX_CSTRING tbl_name= null_clex_str;
|
||||
|
||||
DBUG_ENTER("add_table_for_trigger");
|
||||
DBUG_ENTER("add_table_for_trigger_internal");
|
||||
|
||||
build_trn_path(thd, trg_name, (LEX_STRING*) &trn_path);
|
||||
|
||||
@ -1905,6 +1940,23 @@ bool add_table_for_trigger(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Same as above, but with an allocated buffer.
|
||||
This is called by mysql_excute_command() in is here to keep stack
|
||||
space down in the caller.
|
||||
*/
|
||||
|
||||
bool add_table_for_trigger(THD *thd,
|
||||
const sp_name *trg_name,
|
||||
bool if_exists,
|
||||
TABLE_LIST **table)
|
||||
{
|
||||
char trn_path_buff[FN_REFLEN];
|
||||
return add_table_for_trigger_internal(thd, trg_name, if_exists,
|
||||
table, trn_path_buff);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Drop all triggers for table.
|
||||
|
||||
|
Reference in New Issue
Block a user