summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
authorunknown <dlenev@mockturtle.local>2007-05-19 10:58:01 +0400
committerunknown <dlenev@mockturtle.local>2007-05-19 10:58:01 +0400
commit3d01594f349a540068943b1ba7ddea2ec2e448ef (patch)
tree7c5a80278b1be15a8b7766f9fae0fe02f4dae781 /sql/sql_table.cc
parentad4da53510fe17b7b20912753232719fd8d3e033 (diff)
parent1a60685cbaf6bcd919189ac19f01f65c50d79b54 (diff)
downloadmariadb-git-3d01594f349a540068943b1ba7ddea2ec2e448ef.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into mockturtle.local:/home/dlenev/src/mysql-5.1-alter sql/sql_base.cc: Auto merged
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r--sql/sql_table.cc228
1 files changed, 87 insertions, 141 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index df336545460..149c746a1de 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -5406,7 +5406,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_CREATE_INFO *create_info;
frm_type_enum frm_type;
uint need_copy_table= 0;
- bool no_table_reopen= FALSE, varchar= FALSE;
+ bool varchar= FALSE;
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition= 0;
bool partition_changed= FALSE;
@@ -5665,6 +5665,7 @@ view_err:
VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
/* COND_refresh will be signaled in close_thread_tables() */
break;
@@ -6580,9 +6581,19 @@ view_err:
}
/*
- Data is copied. Now we rename the old table to a temp name,
- rename the new one to the old name, remove all entries about the old table
- from the cache, free all locks, close the old table and remove it.
+ Data is copied. Now we:
+ 1) Wait until all other threads close old version of table.
+ 2) Close instances of table open by this thread and replace them
+ with exclusive name-locks.
+ 3) Rename the old table to a temp name, rename the new one to the
+ old name.
+ 4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
+ we reopen new version of table.
+ 5) Write statement to the binary log.
+ 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
+ remove name-locks from list of open tables and table cache.
+ 7) If we are not not under LOCK TABLES we rely on close_thread_tables()
+ call to remove name-locks from table cache and list of open table.
*/
thd->proc_info="rename result table";
@@ -6591,38 +6602,8 @@ view_err:
if (lower_case_table_names)
my_casedn_str(files_charset_info, old_name);
-#if !defined( __WIN__)
- if (table->file->has_transactions())
-#endif
- {
- /*
- Win32 and InnoDB can't drop a table that is in use, so we must
- close the original table before doing the rename
- */
- close_cached_table(thd, table);
- table=0; // Marker that table is closed
- no_table_reopen= TRUE;
- }
-#if !defined( __WIN__)
- else
- table->file->extra(HA_EXTRA_FORCE_REOPEN); // Don't use this file anymore
-#endif
-
- if (new_name != table_name || new_db != db)
- {
- /*
- Check that there is no table with target name. See the
- comment describing code for 'simple' ALTER TABLE ... RENAME.
- */
- if (!access(new_name_buff,F_OK))
- {
- error=1;
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- }
+ wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE);
+ close_data_files_and_morph_locks(thd, db, table_name);
error=0;
save_old_db_type= old_db_type;
@@ -6667,121 +6648,64 @@ view_err:
if (error)
{
- /*
- This shouldn't happen. We solve this the safe way by
- closing the locked table.
- */
- if (table)
- {
- close_cached_table(thd,table);
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
+ /* This shouldn't happen. But let us play it safe. */
+ goto err_with_placeholders;
}
+
if (! need_copy_table)
{
- bool needs_unlink= FALSE;
- if (! table)
- {
- if (new_name != table_name || new_db != db)
- {
- table_list->alias= new_name;
- table_list->table_name= new_name;
- table_list->table_name_length= strlen(new_name);
- table_list->db= new_db;
- table_list->db_length= strlen(new_db);
- }
- else
- {
- /*
- TODO: Creation of name-lock placeholder here is a temporary
- work-around. Long term we should change close_cached_table() call
- which we invoke before table renaming operation in such way that
- it will leave placeholders for table in table cache/THD::open_tables
- list. By doing this we will be able easily reopen and relock these
- tables later and therefore behave under LOCK TABLES in the same way
- on all platforms.
- */
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
- key_length= create_table_def_key(thd, key, table_list, 0);
- if (!(name_lock= table_cache_insert_placeholder(thd, key,
- key_length)))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- name_lock->next= thd->open_tables;
- thd->open_tables= name_lock;
- }
+ /*
+ Now we have to inform handler that new .FRM file is in place.
+ To do this we need to obtain a handler object for it.
+ */
+ TABLE *t_table;
+ if (new_name != table_name || new_db != db)
+ {
+ table_list->alias= new_name;
+ table_list->table_name= new_name;
+ table_list->table_name_length= strlen(new_name);
+ table_list->db= new_db;
+ table_list->db_length= strlen(new_db);
table_list->table= name_lock;
if (reopen_name_locked_table(thd, table_list, FALSE))
- {
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- table= table_list->table;
- /*
- We can't rely on later close_cached_table() calls to close
- this instance of the table since it was not properly locked.
- */
- needs_unlink= TRUE;
+ goto err_with_placeholders;
+ t_table= table_list->table;
}
- /* Tell the handler that a new frm file is in place. */
- if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG,
- create_info))
+ else
{
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
+ if (reopen_table(table))
+ goto err_with_placeholders;
+ t_table= table;
}
- if (needs_unlink)
+ /* Tell the handler that a new frm file is in place. */
+ if (t_table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG,
+ create_info))
+ goto err_with_placeholders;
+ if (thd->locked_tables && new_name == table_name && new_db == db)
{
- unlink_open_table(thd, table, FALSE);
- table= name_lock= 0;
+ /*
+ We are going to reopen table down on the road, so we have to restore
+ state of the TABLE object which we used for obtaining of handler
+ object to make it suitable for reopening.
+ */
+ DBUG_ASSERT(t_table == table);
+ table->open_placeholder= 1;
+ close_handle_and_leave_table_as_lock(table);
}
}
- if (thd->lock || new_name != table_name || no_table_reopen) // True if WIN32
- {
- /*
- Not table locking or alter table with rename.
- Free locks and remove old table
- */
- if (table)
- {
- close_cached_table(thd,table);
- }
- VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
- }
- else
+ VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
+
+ if (thd->locked_tables && new_name == table_name && new_db == db)
{
- /*
- Using LOCK TABLES without rename.
- This code is never executed on WIN32!
- Remove old renamed table, reopen table and get new locks
- */
- if (table)
- {
- VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
- /* Mark in-use copies old */
- remove_table_from_cache(thd,db,table_name,RTFC_NO_FLAG);
- /* end threads waiting on lock */
- mysql_lock_abort(thd,table, TRUE);
- }
- VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
- if (close_data_tables(thd,db,table_name) ||
- reopen_tables(thd,1,0))
- { // This shouldn't happen
- if (table)
- {
- close_cached_table(thd,table); // Remove lock for table
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
+ thd->in_lock_tables= 1;
+ error= reopen_tables(thd, 1, 0);
+ thd->in_lock_tables= 0;
+ if (error)
+ goto err_with_placeholders;
}
VOID(pthread_mutex_unlock(&LOCK_open));
- broadcast_refresh();
+
/*
The ALTER TABLE is always in its own transaction.
Commit must not be called while LOCK_open is locked. It could call
@@ -6798,6 +6722,8 @@ view_err:
}
thd->proc_info="end";
+ DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
+
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
thd->query, thd->query_length,
db, table_name);
@@ -6815,12 +6741,13 @@ view_err:
shutdown.
*/
char path[FN_REFLEN];
+ TABLE *t_table;
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
- table=open_temporary_table(thd, path, new_db, tmp_name,0);
- if (table)
+ t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
+ if (t_table)
{
- intern_close_table(table);
- my_free((char*) table, MYF(0));
+ intern_close_table(t_table);
+ my_free((char*) t_table, MYF(0));
}
else
sql_print_warning("Could not open table %s.%s after rename\n",
@@ -6830,9 +6757,16 @@ view_err:
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
- if (name_lock)
+ if (thd->locked_tables && (new_name != table_name || new_db != db))
{
+ /*
+ If are we under LOCK TABLES and did ALTER TABLE with RENAME we need
+ to remove placeholders for the old table and for the target table
+ from the list of open tables and table cache. If we are not under
+ LOCK TABLES we can rely on close_thread_tables() doing this job.
+ */
pthread_mutex_lock(&LOCK_open);
+ unlink_open_table(thd, table, FALSE);
unlink_open_table(thd, name_lock, FALSE);
pthread_mutex_unlock(&LOCK_open);
}
@@ -6863,6 +6797,18 @@ err:
pthread_mutex_unlock(&LOCK_open);
}
DBUG_RETURN(TRUE);
+
+err_with_placeholders:
+ /*
+ An error happened while we were holding exclusive name-lock on table
+ being altered. To be safe under LOCK TABLES we should remove placeholders
+ from list of open tables list and table cache.
+ */
+ unlink_open_table(thd, table, FALSE);
+ if (name_lock)
+ unlink_open_table(thd, name_lock, FALSE);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(TRUE);
}
/* mysql_alter_table */