Commit 67770b76 authored by unknown's avatar unknown

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.
parent b6248f76
...@@ -54,3 +54,13 @@ Tables_in_test ...@@ -54,3 +54,13 @@ Tables_in_test
t2 t2
t4 t4
drop table 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; ...@@ -72,4 +72,17 @@ disconnect con2;
disconnect con1; disconnect con1;
connection default; 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 # End of 4.1 tests
...@@ -648,6 +648,9 @@ int quick_rm_table(enum db_type base,const char *db, ...@@ -648,6 +648,9 @@ int quick_rm_table(enum db_type base,const char *db,
const char *table_name); const char *table_name);
void close_cached_table(THD *thd, TABLE *table); void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); 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); bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
void mysql_parse(THD *thd,char *inBuf,uint length); void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
......
...@@ -126,38 +126,49 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list) ...@@ -126,38 +126,49 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list)
/* /*
Rename all tables in list; Return pointer to wrong entry if something goes Rename a single table or a view
wrong. Note that the table_list may be empty!
*/
static TABLE_LIST * SYNPOSIS
rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) do_rename()
{ thd Thread handle
TABLE_LIST *ren_table,*new_table; ren_table A table/view to be renamed
frm_type_enum frm_type; new_db The database to which the table to be moved to
db_type table_type; new_table_name The new table/view name
new_table_alias The new table/view alias
skip_error Whether to skip error
DBUG_ENTER("rename_tables"); DESCRIPTION
Rename a single table or a view.
for (ren_table= table_list; ren_table; ren_table= new_table->next_local) 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; int rc= 1;
char name[FN_REFLEN]; char name[FN_REFLEN];
const char *new_alias, *old_alias; const char *new_alias, *old_alias;
frm_type_enum frm_type;
db_type table_type;
DBUG_ENTER("do_rename");
new_table= ren_table->next_local;
if (lower_case_table_names == 2) if (lower_case_table_names == 2)
{ {
old_alias= ren_table->alias; old_alias= ren_table->alias;
new_alias= new_table->alias; new_alias= new_table_alias;
} }
else else
{ {
old_alias= ren_table->table_name; old_alias= ren_table->table_name;
new_alias= new_table->table_name; new_alias= new_table_name;
} }
sprintf(name,"%s/%s/%s%s",mysql_data_home, sprintf(name,"%s/%s/%s%s",mysql_data_home,
new_table->db, new_alias, reg_ext); new_db, new_alias, reg_ext);
unpack_filename(name, name); unpack_filename(name, name);
if (!access(name,F_OK)) if (!access(name,F_OK))
{ {
...@@ -179,11 +190,11 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ...@@ -179,11 +190,11 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
else else
{ {
if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias, if (!(rc= mysql_rename_table(table_type, ren_table->db, old_alias,
new_table->db, new_alias))) new_db, new_alias)))
{ {
if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db, if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db,
old_alias, old_alias,
new_table->db, new_db,
new_alias))) new_alias)))
{ {
/* /*
...@@ -192,7 +203,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ...@@ -192,7 +203,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
triggers appropriately. So let us revert operations on .frm triggers appropriately. So let us revert operations on .frm
and handler's data and report about failure to rename table. and handler's data and report about failure to rename table.
*/ */
(void) mysql_rename_table(table_type, new_table->db, new_alias, (void) mysql_rename_table(table_type, new_db, new_alias,
ren_table->db, old_alias); ren_table->db, old_alias);
} }
} }
...@@ -201,9 +212,9 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ...@@ -201,9 +212,9 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
} }
case FRMTYPE_VIEW: case FRMTYPE_VIEW:
/* change of schema is not allowed */ /* change of schema is not allowed */
if (strcmp(ren_table->db, new_table->db)) if (strcmp(ren_table->db, new_db))
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db, my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
new_table->db); new_db);
else else
rc= mysql_rename_view(thd, new_alias, ren_table); rc= mysql_rename_view(thd, new_alias, ren_table);
break; break;
...@@ -214,6 +225,47 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ...@@ -214,6 +225,47 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
break; break;
} }
if (rc && !skip_error) 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, *tmp_table;
DBUG_ENTER("rename_tables");
for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
{
new_table= ren_table->next_local;
if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
new_table->alias, skip_error))
DBUG_RETURN(ren_table); DBUG_RETURN(ren_table);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
......
...@@ -3154,9 +3154,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3154,9 +3154,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
ha_rows copied,deleted; ha_rows copied,deleted;
ulonglong next_insert_id; ulonglong next_insert_id;
uint db_create_options, used_fields; 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 need_copy_table;
bool no_table_reopen= FALSE, varchar= FALSE; bool no_table_reopen= FALSE, varchar= FALSE;
frm_type_enum frm_type;
DBUG_ENTER("mysql_alter_table"); DBUG_ENTER("mysql_alter_table");
thd->proc_info="init"; thd->proc_info="init";
...@@ -3174,6 +3175,51 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3174,6 +3175,51 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (alter_info->tablespace_op != NO_TABLESPACE_OP) if (alter_info->tablespace_op != NO_TABLESPACE_OP)
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
alter_info->tablespace_op)); 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))) if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment