diff options
Diffstat (limited to 'sql/sql_rename.cc')
-rw-r--r-- | sql/sql_rename.cc | 138 |
1 files changed, 117 insertions, 21 deletions
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index f6766aec285..f34ec83b29c 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -31,10 +31,13 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list); second entry is the new name. */ -bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) +bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) { bool error= 1; TABLE_LIST *ren_table= 0; + int to_table; + char *rename_log_table[2]= {NULL, NULL}; + int disable_logs= 0; DBUG_ENTER("mysql_rename_tables"); /* @@ -51,6 +54,96 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) if (wait_if_global_read_lock(thd,0,1)) DBUG_RETURN(1); + + if (logger.is_log_table_enabled(QUERY_LOG_GENERAL) || + logger.is_log_table_enabled(QUERY_LOG_SLOW)) + { + + /* + Rules for rename of a log table: + + IF 1. Log tables are enabled + AND 2. Rename operates on the log table and nothing is being + renamed to the log table. + DO 3. Throw an error message. + ELSE 4. Perform rename. + */ + + for (to_table= 0, ren_table= table_list; ren_table; + to_table= 1 - to_table, ren_table= ren_table->next_local) + { + int log_table_rename= 0; + + if ((log_table_rename= + check_if_log_table(ren_table->db_length, ren_table->db, + ren_table->table_name_length, + ren_table->table_name, 1))) + { + /* + Log table encoutered we will need to disable and lock logs + for duration of rename. + */ + disable_logs= TRUE; + + /* + as we use log_table_rename as an array index, we need it to start + with 0, while QUERY_LOG_SLOW == 1 and QUERY_LOG_GENERAL == 2. + So, we shift the value to start with 0; + */ + log_table_rename--; + if (rename_log_table[log_table_rename]) + { + if (to_table) + rename_log_table[log_table_rename]= NULL; + else + { + /* + Two renames of "log_table TO" w/o rename "TO log_table" in + between. + */ + my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, + ren_table->table_name); + DBUG_RETURN(1); + } + } + else + { + if (to_table) + { + /* + Attempt to rename a table TO log_table w/o renaming + log_table TO some table. + */ + my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, + ren_table->table_name); + DBUG_RETURN(1); + } + else + { + /* save the name of the log table to report an error */ + rename_log_table[log_table_rename]= ren_table->table_name; + } + } + } + } + if (rename_log_table[0] || rename_log_table[1]) + { + if (rename_log_table[0]) + my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), rename_log_table[0], + rename_log_table[0]); + else + my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), rename_log_table[1], + rename_log_table[1]); + DBUG_RETURN(1); + } + + if (disable_logs) + { + logger.lock(); + logger.tmp_close_log_tables(thd); + } + } + VOID(pthread_mutex_lock(&LOCK_open)); if (lock_table_names(thd, table_list)) goto err; @@ -79,13 +172,13 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) } /* Lets hope this doesn't fail as the result will be messy */ - if (!error) + if (!silent && !error) { if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::STMT_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); } send_ok(thd); } @@ -94,6 +187,13 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) err: pthread_mutex_unlock(&LOCK_open); + /* enable logging back if needed */ + if (disable_logs) + { + if (logger.reopen_log_tables()) + error= TRUE; + logger.unlock(); + } start_waiting_global_read_lock(thd); DBUG_RETURN(error); } @@ -152,7 +252,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, char name[FN_REFLEN]; const char *new_alias, *old_alias; frm_type_enum frm_type; - db_type table_type; + enum legacy_db_type table_type; DBUG_ENTER("do_rename"); @@ -166,30 +266,25 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, old_alias= ren_table->table_name; new_alias= new_table_name; } - sprintf(name,"%s/%s/%s%s",mysql_data_home, - new_db, new_alias, reg_ext); - unpack_filename(name, name); + build_table_filename(name, sizeof(name), + new_db, new_alias, reg_ext, 0); if (!access(name,F_OK)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); DBUG_RETURN(1); // This can't be skipped } - sprintf(name,"%s/%s/%s%s",mysql_data_home, - ren_table->db, old_alias, - reg_ext); - unpack_filename(name, name); + build_table_filename(name, sizeof(name), + ren_table->db, old_alias, reg_ext, 0); frm_type= mysql_frm_type(thd, name, &table_type); switch (frm_type) { case FRMTYPE_TABLE: - { - if (table_type == DB_TYPE_UNKNOWN) - my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); - else { - if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias, - new_db, new_alias))) + if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd, + table_type), + ren_table->db, old_alias, + new_db, new_alias, 0))) { if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db, old_alias, @@ -202,13 +297,14 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, triggers appropriately. So let us revert operations on .frm and handler's data and report about failure to rename table. */ - (void) mysql_rename_table(table_type, new_db, new_alias, - ren_table->db, old_alias); + (void) mysql_rename_table(ha_resolve_by_legacy_type(thd, + table_type), + new_db, new_alias, + ren_table->db, old_alias, 0); } } } break; - } case FRMTYPE_VIEW: /* change of schema is not allowed */ if (strcmp(ren_table->db, new_db)) |