From: eugene Date: October 13 2006 5:59pm Subject: bk commit into 5.0 tree (evgen:1.2299) BUG#14959 List-Archive: http://lists.mysql.com/commits/13678 X-Bug: 14959 Message-Id: <20061013175955.A74262BDFF@moonbone.moonbone.local> Below is the list of changes that have just been committed into a local 5.0 repository of evgen. When evgen does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2006-10-13 21:59:52+04:00, evgen@stripped +5 -0 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/r/rename.result@stripped, 2006-10-13 21:51:04+04:00, evgen@stripped +10 -0 Added a test case for bug#14959: ALTER TABLE isn't able to rename a view mysql-test/t/rename.test@stripped, 2006-10-13 21:47:00+04:00, evgen@stripped +13 -0 Added a test case for bug#14959: ALTER TABLE isn't able to rename a view sql/mysql_priv.h@stripped, 2006-10-13 21:56:45+04:00, evgen@stripped +3 -0 Bug#14959: ALTER TABLE isn't able to rename a view Added the prototype of the do_rename() function. sql/sql_rename.cc@stripped, 2006-10-13 21:57:58+04:00, evgen@stripped +123 -71 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@stripped, 2006-10-13 21:58:16+04:00, evgen@stripped +47 -1 Bug#14959: ALTER TABLE isn't able to rename a view Added handling of a view rename to the mysql_alter_table() function. # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: evgen # Host: moonbone.local # Root: /work/14959-bug-5.0-opt-mysql --- 1.412/sql/mysql_priv.h 2006-10-13 21:59:55 +04:00 +++ 1.413/sql/mysql_priv.h 2006-10-13 21:59:55 +04:00 @@ -648,6 +648,9 @@ 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); --- 1.321/sql/sql_table.cc 2006-10-13 21:59:55 +04:00 +++ 1.322/sql/sql_table.cc 2006-10-13 21:59:55 +04:00 @@ -3154,9 +3154,10 @@ 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 @@ 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); --- 1.12/mysql-test/r/rename.result 2006-10-13 21:59:55 +04:00 +++ 1.13/mysql-test/r/rename.result 2006-10-13 21:59:55 +04:00 @@ -54,3 +54,13 @@ 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; --- 1.12/mysql-test/t/rename.test 2006-10-13 21:59:55 +04:00 +++ 1.13/mysql-test/t/rename.test 2006-10-13 21:59:55 +04:00 @@ -72,4 +72,17 @@ 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 --- 1.32/sql/sql_rename.cc 2006-10-13 21:59:55 +04:00 +++ 1.33/sql/sql_rename.cc 2006-10-13 21:59:55 +04:00 @@ -126,94 +126,146 @@ /* - Rename all tables in list; Return pointer to wrong entry if something goes - wrong. Note that the table_list may be empty! + 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 */ -static TABLE_LIST * -rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) +bool +do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, + char *new_table_alias, bool skip_error) { - TABLE_LIST *ren_table,*new_table; + int rc= 1; + char name[FN_REFLEN]; + const char *new_alias, *old_alias; frm_type_enum frm_type; db_type table_type; - DBUG_ENTER("rename_tables"); + DBUG_ENTER("do_rename"); - for (ren_table= table_list; ren_table; ren_table= new_table->next_local) + if (lower_case_table_names == 2) { - 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); + 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) + frm_type= mysql_frm_type(thd, name, &table_type); + switch (frm_type) + { + case FRMTYPE_TABLE: { - case FRMTYPE_TABLE: + if (table_type == DB_TYPE_UNKNOWN) + my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); + else { - 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(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_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); - } + /* + 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_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; + break; } - if (rc && !skip_error) + 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, *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(0);