Commit 67770b76 authored by unknown's avatar unknown
Browse files

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
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
+13 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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);
+123 −71
Original line number Diff line number Diff line
@@ -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
  wrong.  Note that the table_list may be empty!
*/
  Rename a single table or a view

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;
  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

  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;
  char name[FN_REFLEN];
  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)
  {
    old_alias= ren_table->alias;
      new_alias= new_table->alias;
    new_alias= new_table_alias;
  }
  else
  {
    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,
	    new_table->db, new_alias, reg_ext);
          new_db, new_alias, reg_ext);
  unpack_filename(name, name);
  if (!access(name,F_OK))
  {
@@ -179,11 +190,11 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
      else
      {
        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,
                                                          old_alias,
                                                            new_table->db,
                                                          new_db,
                                                          new_alias)))
          {
            /*
@@ -192,7 +203,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
              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,
            (void) mysql_rename_table(table_type, new_db, new_alias,
                                      ren_table->db, old_alias);
          }
        }
@@ -201,9 +212,9 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
    }
    case FRMTYPE_VIEW:
      /* 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, 
                   new_table->db);
                 new_db);
      else
        rc= mysql_rename_view(thd, new_alias, ren_table);
      break;
@@ -214,6 +225,47 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
      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);
+47 −1
Original line number Diff line number Diff line
@@ -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);