mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains triggers and #41385: Crash when attempting to repair a #mysql50# upgraded table with triggers. Problem: 1. trigger code didn't assume a table name may have a "#mysql50#" prefix, that may lead to a failing ASSERT(). 2. "ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME" failed for databases with "#mysql50#" prefix if any trigger. 3. mysqlcheck --fix-table-name didn't use UTF8 as a default character set that resulted in (parsing) errors for tables with non-latin symbols in their names and definitions of triggers. Fix: 1. properly handle table/database names with "#mysql50#" prefix. 2. handle --default-character-set mysqlcheck option; if mysqlcheck is launched with --fix-table-name or --fix-db-name set default character set to UTF8 if no --default-character-set option given. Note: if given --fix-table-name or --fix-db-name option, without --default-character-set mysqlcheck option default character set is UTF8.
This commit is contained in:
@ -1368,15 +1368,27 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
|
||||
if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
Let us check that we correctly update trigger definitions when we
|
||||
rename tables with triggers.
|
||||
|
||||
In special cases like "RENAME TABLE `#mysql50#somename` TO `somename`"
|
||||
or "ALTER DATABASE `#mysql50#somename` UPGRADE DATA DIRECTORY NAME"
|
||||
we might be given table or database name with "#mysql50#" prefix (and
|
||||
trigger's definiton contains un-prefixed version of the same name).
|
||||
To remove this prefix we use check_n_cut_mysql50_prefix().
|
||||
*/
|
||||
DBUG_ASSERT(!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
|
||||
table_name));
|
||||
|
||||
char fname[NAME_LEN + 1];
|
||||
DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) ||
|
||||
(check_n_cut_mysql50_prefix(db, fname, sizeof(fname)) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->db, fname))) &&
|
||||
(!my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
|
||||
table_name) ||
|
||||
(check_n_cut_mysql50_prefix(table_name, fname, sizeof(fname)) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->table_name, fname))));
|
||||
#endif
|
||||
if (names_only)
|
||||
{
|
||||
lex_end(&lex);
|
||||
@ -1692,7 +1704,8 @@ end:
|
||||
(change name of table in triggers' definitions).
|
||||
|
||||
@param thd Thread context
|
||||
@param db_name Database of subject table
|
||||
@param old_db_name Old database of subject table
|
||||
@param new_db_name New database of subject table
|
||||
@param old_table_name Old subject table's name
|
||||
@param new_table_name New subject table's name
|
||||
|
||||
@ -1704,7 +1717,8 @@ end:
|
||||
|
||||
bool
|
||||
Table_triggers_list::change_table_name_in_triggers(THD *thd,
|
||||
const char *db_name,
|
||||
const char *old_db_name,
|
||||
const char *new_db_name,
|
||||
LEX_STRING *old_table_name,
|
||||
LEX_STRING *new_table_name)
|
||||
{
|
||||
@ -1757,11 +1771,11 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
|
||||
if (thd->is_fatal_error)
|
||||
return TRUE; /* OOM */
|
||||
|
||||
if (save_trigger_file(this, db_name, new_table_name->str))
|
||||
if (save_trigger_file(this, new_db_name, new_table_name->str))
|
||||
return TRUE;
|
||||
if (rm_trigger_file(path_buff, db_name, old_table_name->str))
|
||||
if (rm_trigger_file(path_buff, old_db_name, old_table_name->str))
|
||||
{
|
||||
(void) rm_trigger_file(path_buff, db_name, new_table_name->str);
|
||||
(void) rm_trigger_file(path_buff, new_db_name, new_table_name->str);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -1772,7 +1786,8 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
|
||||
Iterate though Table_triggers_list::names_list list and update
|
||||
.TRN files after renaming triggers' subject table.
|
||||
|
||||
@param db_name Database of subject table
|
||||
@param old_db_name Old database of subject table
|
||||
@param new_db_name New database of subject table
|
||||
@param new_table_name New subject table's name
|
||||
@param stopper Pointer to Table_triggers_list::names_list at
|
||||
which we should stop updating.
|
||||
@ -1785,7 +1800,8 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
|
||||
*/
|
||||
|
||||
LEX_STRING*
|
||||
Table_triggers_list::change_table_name_in_trignames(const char *db_name,
|
||||
Table_triggers_list::change_table_name_in_trignames(const char *old_db_name,
|
||||
const char *new_db_name,
|
||||
LEX_STRING *new_table_name,
|
||||
LEX_STRING *stopper)
|
||||
{
|
||||
@ -1798,7 +1814,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
|
||||
while ((trigger= it_name++) != stopper)
|
||||
{
|
||||
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
|
||||
db_name, trigger->str,
|
||||
new_db_name, trigger->str,
|
||||
TRN_EXT, 0);
|
||||
trigname_file.str= trigname_buff;
|
||||
|
||||
@ -1807,6 +1823,16 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
|
||||
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
|
||||
(uchar*)&trigname, trigname_file_parameters))
|
||||
return trigger;
|
||||
|
||||
/* Remove stale .TRN file in case of database upgrade */
|
||||
if (old_db_name)
|
||||
{
|
||||
if (rm_trigname_file(trigname_buff, old_db_name, trigger->str))
|
||||
{
|
||||
(void) rm_trigname_file(trigname_buff, new_db_name, trigger->str);
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1840,6 +1866,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
{
|
||||
TABLE table;
|
||||
bool result= 0;
|
||||
bool upgrading50to51= FALSE;
|
||||
LEX_STRING *err_trigname;
|
||||
DBUG_ENTER("change_table_name");
|
||||
|
||||
@ -1877,14 +1904,27 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
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 ?).
|
||||
|
||||
In case of "ALTER DATABASE `#mysql50#db1` UPGRADE DATA DIRECTORY NAME"
|
||||
we will be given table name with "#mysql50#" prefix
|
||||
To remove this prefix we use check_n_cut_mysql50_prefix().
|
||||
*/
|
||||
if (my_strcasecmp(table_alias_charset, db, new_db))
|
||||
{
|
||||
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
|
||||
result= 1;
|
||||
goto end;
|
||||
char dbname[NAME_LEN + 1];
|
||||
if (check_n_cut_mysql50_prefix(db, dbname, sizeof(dbname)) &&
|
||||
!my_strcasecmp(table_alias_charset, dbname, new_db))
|
||||
{
|
||||
upgrading50to51= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (table.triggers->change_table_name_in_triggers(thd, db,
|
||||
if (table.triggers->change_table_name_in_triggers(thd, db, new_db,
|
||||
&old_table_name,
|
||||
&new_table_name))
|
||||
{
|
||||
@ -1892,7 +1932,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
goto end;
|
||||
}
|
||||
if ((err_trigname= table.triggers->change_table_name_in_trignames(
|
||||
db, &new_table_name, 0)))
|
||||
upgrading50to51 ? db : NULL,
|
||||
new_db, &new_table_name, 0)))
|
||||
{
|
||||
/*
|
||||
If we were unable to update one of .TRN files properly we will
|
||||
@ -1900,16 +1941,17 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *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(db,
|
||||
&old_table_name,
|
||||
err_trigname);
|
||||
(void) table.triggers->change_table_name_in_triggers(thd, db,
|
||||
&new_table_name,
|
||||
&old_table_name);
|
||||
(void) table.triggers->change_table_name_in_trignames(
|
||||
upgrading50to51 ? new_db : NULL, db,
|
||||
&old_table_name, err_trigname);
|
||||
(void) table.triggers->change_table_name_in_triggers(
|
||||
thd, db, new_db,
|
||||
&new_table_name, &old_table_name);
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
delete table.triggers;
|
||||
free_root(&table.mem_root, MYF(0));
|
||||
|
Reference in New Issue
Block a user