Bug#14959: ALTER TABLE isn't able to rename a view
The mysql_alter_table() was able to rename only a table. The view/table renaming code is moved from the function rename_tables to the new function called do_rename(). The mysql_alter_table() function calls it when it needs to rename a view. mysql-test/t/rename.test: Added a test case for bug#14959: ALTER TABLE isn't able to rename a view mysql-test/r/rename.result: Added a test case for bug#14959: ALTER TABLE isn't able to rename a view sql/mysql_priv.h: Bug#14959: ALTER TABLE isn't able to rename a view Added the prototype of the do_rename() function. sql/sql_rename.cc: Bug#14959: ALTER TABLE isn't able to rename a view The view/table renaming code is moved from the function rename_tables to the new function called do_rename(). sql/sql_table.cc: Bug#14959: ALTER TABLE isn't able to rename a view Added handling of a view rename to the mysql_alter_table() function.
This commit is contained in:
parent
b6248f76ed
commit
67770b7671
@ -54,3 +54,13 @@ Tables_in_test
|
||||
t2
|
||||
t4
|
||||
drop table t2, t4;
|
||||
create table t1(f1 int);
|
||||
create view v1 as select * from t1;
|
||||
alter table v1 rename to v2;
|
||||
alter table v1 rename to v2;
|
||||
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||
rename table v2 to v1;
|
||||
rename table v2 to v1;
|
||||
ERROR 42S01: Table 'v1' already exists
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
|
@ -72,4 +72,17 @@ disconnect con2;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
|
||||
#
|
||||
# Bug#14959: ALTER TABLE isn't able to rename a view
|
||||
#
|
||||
create table t1(f1 int);
|
||||
create view v1 as select * from t1;
|
||||
alter table v1 rename to v2;
|
||||
--error 1146
|
||||
alter table v1 rename to v2;
|
||||
rename table v2 to v1;
|
||||
--error 1050
|
||||
rename table v2 to v1;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
# End of 4.1 tests
|
||||
|
@ -648,6 +648,9 @@ int quick_rm_table(enum db_type base,const char *db,
|
||||
const char *table_name);
|
||||
void close_cached_table(THD *thd, TABLE *table);
|
||||
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
|
||||
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
|
||||
char *new_table_name, char *new_table_alias,
|
||||
bool skip_error);
|
||||
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
|
||||
void mysql_parse(THD *thd,char *inBuf,uint length);
|
||||
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
|
||||
|
@ -125,95 +125,147 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Rename a single table or a view
|
||||
|
||||
SYNPOSIS
|
||||
do_rename()
|
||||
thd Thread handle
|
||||
ren_table A table/view to be renamed
|
||||
new_db The database to which the table to be moved to
|
||||
new_table_name The new table/view name
|
||||
new_table_alias The new table/view alias
|
||||
skip_error Whether to skip error
|
||||
|
||||
DESCRIPTION
|
||||
Rename a single table or a view.
|
||||
|
||||
RETURN
|
||||
false Ok
|
||||
true rename failed
|
||||
*/
|
||||
|
||||
bool
|
||||
do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
|
||||
char *new_table_alias, bool skip_error)
|
||||
{
|
||||
int rc= 1;
|
||||
char name[FN_REFLEN];
|
||||
const char *new_alias, *old_alias;
|
||||
frm_type_enum frm_type;
|
||||
db_type table_type;
|
||||
|
||||
DBUG_ENTER("do_rename");
|
||||
|
||||
if (lower_case_table_names == 2)
|
||||
{
|
||||
old_alias= ren_table->alias;
|
||||
new_alias= new_table_alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
if (!access(name,F_OK))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
||||
DBUG_RETURN(ren_table); // 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);
|
||||
|
||||
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= Table_triggers_list::change_table_name(thd, ren_table->db,
|
||||
old_alias,
|
||||
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(table_type, new_db, new_alias,
|
||||
ren_table->db, old_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRMTYPE_VIEW:
|
||||
/* change of schema is not allowed */
|
||||
if (strcmp(ren_table->db, new_db))
|
||||
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
|
||||
new_db);
|
||||
else
|
||||
rc= mysql_rename_view(thd, new_alias, ren_table);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0); // should never happen
|
||||
case FRMTYPE_ERROR:
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
break;
|
||||
}
|
||||
if (rc && !skip_error)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
|
||||
}
|
||||
/*
|
||||
Rename all tables in list; Return pointer to wrong entry if something goes
|
||||
wrong. Note that the table_list may be empty!
|
||||
*/
|
||||
|
||||
/*
|
||||
Rename tables/views in the list
|
||||
|
||||
SYNPOSIS
|
||||
rename_tables()
|
||||
thd Thread handle
|
||||
table_list List of tables to rename
|
||||
skip_error Whether to skip errors
|
||||
|
||||
DESCRIPTION
|
||||
Take a table/view name from and odd list element and rename it to a
|
||||
the name taken from list element+1. Note that the table_list may be
|
||||
empty.
|
||||
|
||||
RETURN
|
||||
false Ok
|
||||
true rename failed
|
||||
*/
|
||||
|
||||
static TABLE_LIST *
|
||||
rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
||||
{
|
||||
TABLE_LIST *ren_table,*new_table;
|
||||
frm_type_enum frm_type;
|
||||
db_type table_type;
|
||||
TABLE_LIST *ren_table,*new_table, *tmp_table;
|
||||
|
||||
DBUG_ENTER("rename_tables");
|
||||
|
||||
for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
|
||||
{
|
||||
int rc= 1;
|
||||
char name[FN_REFLEN];
|
||||
const char *new_alias, *old_alias;
|
||||
|
||||
new_table= ren_table->next_local;
|
||||
if (lower_case_table_names == 2)
|
||||
{
|
||||
old_alias= ren_table->alias;
|
||||
new_alias= new_table->alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_alias= ren_table->table_name;
|
||||
new_alias= new_table->table_name;
|
||||
}
|
||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||
new_table->db, new_alias, reg_ext);
|
||||
unpack_filename(name, name);
|
||||
if (!access(name,F_OK))
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
||||
DBUG_RETURN(ren_table); // 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);
|
||||
|
||||
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_table->db, new_alias)))
|
||||
{
|
||||
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
|
||||
old_alias,
|
||||
new_table->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(table_type, new_table->db, new_alias,
|
||||
ren_table->db, old_alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRMTYPE_VIEW:
|
||||
/* change of schema is not allowed */
|
||||
if (strcmp(ren_table->db, new_table->db))
|
||||
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
|
||||
new_table->db);
|
||||
else
|
||||
rc= mysql_rename_view(thd, new_alias, ren_table);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0); // should never happen
|
||||
case FRMTYPE_ERROR:
|
||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||
break;
|
||||
}
|
||||
if (rc && !skip_error)
|
||||
if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
|
||||
new_table->alias, skip_error))
|
||||
DBUG_RETURN(ren_table);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
|
@ -3154,9 +3154,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
ha_rows copied,deleted;
|
||||
ulonglong next_insert_id;
|
||||
uint db_create_options, used_fields;
|
||||
enum db_type old_db_type,new_db_type;
|
||||
enum db_type old_db_type, new_db_type, table_type;
|
||||
bool need_copy_table;
|
||||
bool no_table_reopen= FALSE, varchar= FALSE;
|
||||
frm_type_enum frm_type;
|
||||
DBUG_ENTER("mysql_alter_table");
|
||||
|
||||
thd->proc_info="init";
|
||||
@ -3174,6 +3175,51 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
|
||||
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
|
||||
alter_info->tablespace_op));
|
||||
sprintf(new_name_buff,"%s/%s/%s%s",mysql_data_home, db, table_name, reg_ext);
|
||||
unpack_filename(new_name_buff, new_name_buff);
|
||||
if (lower_case_table_names != 2)
|
||||
my_casedn_str(files_charset_info, new_name_buff);
|
||||
frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
|
||||
/* Rename a view */
|
||||
if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
|
||||
{
|
||||
/*
|
||||
Avoid problems with a rename on a table that we have locked or
|
||||
if the user is trying to to do this in a transcation context
|
||||
*/
|
||||
|
||||
if (thd->locked_tables || thd->active_transaction())
|
||||
{
|
||||
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
|
||||
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (wait_if_global_read_lock(thd,0,1))
|
||||
DBUG_RETURN(1);
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (lock_table_names(thd, table_list))
|
||||
goto view_err;
|
||||
|
||||
error=0;
|
||||
if (!do_rename(thd, table_list, new_db, new_name, new_name, 1))
|
||||
{
|
||||
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);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
|
||||
unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
|
||||
|
||||
view_err:
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
start_waiting_global_read_lock(thd);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user