diff options
Diffstat (limited to 'sql/sql_rename.cc')
-rw-r--r-- | sql/sql_rename.cc | 165 |
1 files changed, 105 insertions, 60 deletions
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index ada373546be..77a1e46a75a 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -32,10 +32,13 @@ #include "sql_statistics.h" static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list, - bool skip_error); -static bool do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, - const LEX_CSTRING *new_table_name, const LEX_CSTRING *new_table_alias, - bool skip_error); + bool skip_error, bool if_exits, + bool *force_if_exists); +static bool do_rename(THD *thd, TABLE_LIST *ren_table, + const LEX_CSTRING *new_db, + const LEX_CSTRING *new_table_name, + const LEX_CSTRING *new_table_alias, + bool skip_error, bool if_exists, bool *force_if_exists); static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list); @@ -44,10 +47,11 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list); the new name. */ -bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) +bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent, + bool if_exists) { bool error= 1; - bool binlog_error= 0; + bool binlog_error= 0, force_if_exists; TABLE_LIST *ren_table= 0; int to_table; const char *rename_log_table[2]= {NULL, NULL}; @@ -151,7 +155,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) An exclusive lock on table names is satisfactory to ensure no other thread accesses this table. */ - if ((ren_table=rename_tables(thd,table_list,0))) + if ((ren_table= rename_tables(thd, table_list, 0, if_exists, + &force_if_exists))) { /* Rename didn't succeed; rename back the tables in reverse order */ TABLE_LIST *table; @@ -165,7 +170,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) table= table->next_local->next_local) ; table= table->next_local->next_local; // Skip error table /* Revert to old names */ - rename_tables(thd, table, 1); + rename_tables(thd, table, 1, if_exists, &force_if_exists); /* Revert the table list (for prepared statements) */ table_list= reverse_table_list(table_list); @@ -175,7 +180,15 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) if (likely(!silent && !error)) { + ulonglong save_option_bits= thd->variables.option_bits; + if (force_if_exists && ! if_exists) + { + /* Add IF EXISTS to binary log */ + thd->variables.option_bits|= OPTION_IF_EXISTS; + } binlog_error= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + thd->variables.option_bits= save_option_bits; + if (likely(!binlog_error)) my_ok(thd); } @@ -246,6 +259,9 @@ do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table, new_table_name The new table/view name new_table_alias The new table/view alias skip_error Whether to skip error + if_exists Skip error, but only if the table didn't exists + force_if_exists Set to 1 if we have to log the query with 'IF EXISTS' + Otherwise don't touch the value DESCRIPTION Rename a single table or a view. @@ -257,13 +273,16 @@ do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table, static bool do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, - const LEX_CSTRING *new_table_name, const LEX_CSTRING *new_table_alias, - bool skip_error) + const LEX_CSTRING *new_table_name, + const LEX_CSTRING *new_table_alias, + bool skip_error, bool if_exists, bool *force_if_exists) { int rc= 1; - handlerton *hton; + handlerton *hton, *new_hton; LEX_CSTRING old_alias, new_alias; DBUG_ENTER("do_rename"); + DBUG_PRINT("enter", ("skip_error: %d if_exists: %d", (int) skip_error, + (int) if_exists)); if (lower_case_table_names == 2) { @@ -277,65 +296,86 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, } DBUG_ASSERT(new_alias.str); - if (ha_table_exists(thd, new_db, &new_alias)) + if (!ha_table_exists(thd, &ren_table->db, &old_alias, &hton) || !hton) + { + my_error(ER_NO_SUCH_TABLE, MYF((skip_error | if_exists) ? ME_NOTE : 0), + ren_table->db.str, old_alias.str); + DBUG_RETURN(skip_error || if_exists ? 0 : 1); + } + + if (hton != view_pseudo_hton && + ha_check_if_updates_are_ignored(thd, hton, "RENAME")) + { + /* + Shared table. Just drop the old .frm as it's not correct anymore + Discovery will find the old table when it's accessed + */ + tdc_remove_table(thd, ren_table->db.str, ren_table->table_name.str); + quick_rm_table(thd, 0, &ren_table->db, &old_alias, FRM_ONLY, 0); + DBUG_RETURN(0); + } + + if (ha_table_exists(thd, new_db, &new_alias, &new_hton)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias.str); DBUG_RETURN(1); // This can't be skipped } - if (ha_table_exists(thd, &ren_table->db, &old_alias, &hton) && hton) + DBUG_ASSERT(!thd->locked_tables_mode); + +#ifdef WITH_WSREP + if (WSREP(thd) && hton && hton != view_pseudo_hton && + !wsrep_should_replicate_ddl(thd, hton->db_type)) + DBUG_RETURN(1); +#endif + + tdc_remove_table(thd, ren_table->db.str, ren_table->table_name.str); + + if (hton != view_pseudo_hton) { - DBUG_ASSERT(!thd->locked_tables_mode); - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, - ren_table->db.str, ren_table->table_name.str, false); + if (hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) + *force_if_exists= 1; - if (hton != view_pseudo_hton) + thd->replication_flags= 0; + if (!(rc= mysql_rename_table(hton, &ren_table->db, &old_alias, + new_db, &new_alias, 0))) { - if (!(rc= mysql_rename_table(hton, &ren_table->db, &old_alias, - new_db, &new_alias, 0))) + (void) rename_table_in_stat_tables(thd, &ren_table->db, + &ren_table->table_name, + new_db, &new_alias); + if ((rc= Table_triggers_list::change_table_name(thd, &ren_table->db, + &old_alias, + &ren_table->table_name, + new_db, + &new_alias))) { - (void) rename_table_in_stat_tables(thd, &ren_table->db, - &ren_table->table_name, - new_db, &new_alias); - if ((rc= Table_triggers_list::change_table_name(thd, &ren_table->db, - &old_alias, - &ren_table->table_name, - new_db, - &new_alias))) - { - /* - We've succeeded in renaming table's .frm and in updating - corresponding handler data, but have failed to update table's - triggers appropriately. So let us revert operations on .frm - and handler's data and report about failure to rename table. - */ - (void) mysql_rename_table(hton, new_db, &new_alias, - &ren_table->db, &old_alias, NO_FK_CHECKS); - } + /* + We've succeeded in renaming table's .frm and in updating + corresponding handler data, but have failed to update table's + triggers appropriately. So let us revert operations on .frm + and handler's data and report about failure to rename table. + */ + (void) mysql_rename_table(hton, new_db, &new_alias, + &ren_table->db, &old_alias, NO_FK_CHECKS); } } - else - { - /* - change of schema is not allowed - except of ALTER ...UPGRADE DATA DIRECTORY NAME command - because a view has valid internal db&table names in this case. - */ - if (thd->lex->sql_command != SQLCOM_ALTER_DB_UPGRADE && - cmp(&ren_table->db, new_db)) - my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db.str, new_db->str); - else - rc= mysql_rename_view(thd, new_db, &new_alias, ren_table); - } + if (thd->replication_flags & OPTION_IF_EXISTS) + *force_if_exists= 1; } else { - my_error(ER_NO_SUCH_TABLE, MYF(0), ren_table->db.str, old_alias.str); + /* + Change of schema is not allowed + except of ALTER ...UPGRADE DATA DIRECTORY NAME command + because a view has valid internal db&table names in this case. + */ + if (thd->lex->sql_command != SQLCOM_ALTER_DB_UPGRADE && + cmp(&ren_table->db, new_db)) + my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db.str, new_db->str); + else + rc= mysql_rename_view(thd, new_db, &new_alias, ren_table); } - if (unlikely(rc && !skip_error)) - DBUG_RETURN(1); - - DBUG_RETURN(0); + DBUG_RETURN(rc && !skip_error ? 1 : 0); } @@ -352,6 +392,9 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, thd Thread handle table_list List of tables to rename skip_error Whether to skip errors + if_exists Don't give an error if table doesn't exists + force_if_exists Set to 1 if we have to log the query with 'IF EXISTS' + Otherwise set it to 0 DESCRIPTION Take a table/view name from and odd list element and rename it to a @@ -359,17 +402,19 @@ do_rename(THD *thd, TABLE_LIST *ren_table, const LEX_CSTRING *new_db, empty. RETURN - false Ok - true rename failed + 0 Ok + table pointer to the table list element which rename failed */ static TABLE_LIST * -rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) +rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error, + bool if_exists, bool *force_if_exists) { TABLE_LIST *ren_table, *new_table; - DBUG_ENTER("rename_tables"); + *force_if_exists= 0; + for (ren_table= table_list; ren_table; ren_table= new_table->next_local) { new_table= ren_table->next_local; @@ -377,7 +422,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) if (is_temporary_table(ren_table) ? do_rename_temporary(thd, ren_table, new_table, skip_error) : do_rename(thd, ren_table, &new_table->db, &new_table->table_name, - &new_table->alias, skip_error)) + &new_table->alias, skip_error, if_exists, force_if_exists)) DBUG_RETURN(ren_table); } DBUG_RETURN(0); |