summaryrefslogtreecommitdiff
path: root/sql/sql_rename.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_rename.cc')
-rw-r--r--sql/sql_rename.cc165
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);