TableIdentifier identifier(new_db, lower_case_table_name);
-
if (plugin::StorageEngine::doesTableExist(*session, identifier))
{
/* Table will be closed by Session::executeCommand() */ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
- goto err; error_on_rename= true;
}
}
It should have instead removed the error_on_rename= true; statement. The goto was necessary to skip the code blocks afterwards. Namely, this block of code is now executed when it wasn't before:
/* Open the table so we need to copy the data to it. */
new_table= open_alter_table(session, table, new_db, tmp_name);
if (new_table == NULL)
goto err1;
/* Copy the data if necessary. */
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
session->cuted_fields= 0L;
session->set_proc_info("copy to tmp table");
copied= deleted= 0;
assert(new_table);
/* We don't want update TIMESTAMP fields during ALTER Table. */
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field= new_table->found_next_number_field;
error= copy_data_between_tables(table, new_table, alter_info->create_list, ignore, order_num, order, &copied, &deleted, alter_info->keys_onoff, alter_info->error_if_not_empty);
/* We must not ignore bad input! */
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
if (table->s->tmp_table != STANDARD_TABLE)
{
/* We changed a temporary table */
if (error)
goto err1;
/* Close lock if this is a transactional table */
if (session->lock)
{ mysql_unlock_tables(session, session->lock); session->lock= 0;
}
/* Remove link to old table and rename the new one */
session->close_temporary_table(table);
/* Should pass the 'new_name' as we store table name in the cache */
TableIdentifier alter_identifier(new_db, new_name);
if (new_table->renameAlterTemporaryTable(alter_identifier))
goto err1;
}
else
{
if (new_table)
{
/*
Close the intermediate table that will be the new table.
Note that MERGE tables do not have their children attached here.
*/ new_table->intern_close_table(); free(new_table);
}
/*
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.
*/
/*
This leads to the storage engine (SE) not being notified for renames in mysql_rename_table(), because we just juggle with the FRM and nothing
more. If we have an intermediate table, then we notify the SE that
it should become the actual table. Later, we will recycle the old table.
However, in case of ALTER Table RENAME there might be no intermediate
table. This is when the old and new tables are compatible, according to compare_table(). Then, we need one additional call to
*/
if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
{
error= 1; TableIdentifier identifier(new_db, tmp_name, INTERNAL_TMP_TABLE); quick_rm_table(*session, identifier);
}
else
{
if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
{
/* Try to get everything back. */
error= 1;
if (error)
{
/*
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.
*/ session->unlink_open_table(table);
if (name_lock) session->unlink_open_table(name_lock); pthread_mutex_unlock(&LOCK_open);
return true;
}
/*
* Field::store() may have called my_error(). If this is
* the case, we must not send an ok packet, since
* Diagnostics_area::is_set() will fail an assert.
*/
if (! session->is_error())
{
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), (ulong) (copied + deleted), (ulong) deleted, (ulong) session->cuted_fields);
session->my_ok(copied + deleted, 0, 0L, tmp_name);
session->some_tables_deleted=0;
return false;
}
else
{
/* my_error() was called. Return true (which means error...) */
return true;
}
I believe it was this change which is buggy:
=== modified file 'drizzled/ statement/ alter_table. cc' statement/ alter_table. cc 2010-03-20 21:48:16 +0000 statement/ alter_table. cc 2010-03-22 17:53:05 +0000
--- drizzled/
+++ drizzled/
@@ -795,12 +795,10 @@
}
-
if (plugin:
{
/* Table will be closed by Session:
- goto err;
}
}
It should have instead removed the error_on_rename= true; statement. The goto was necessary to skip the code blocks afterwards. Namely, this block of code is now executed when it wasn't before:
/* Open the table so we need to copy the data to it. */ table(session, table, new_db, tmp_name);
new_table= open_alter_
if (new_table == NULL)
goto err1;
/* Copy the data if necessary. */ >count_ cuted_fields= CHECK_FIELD_WARN; // calc cuted fields >cuted_ fields= 0L; >set_proc_ info("copy to tmp table");
session-
session-
session-
copied= deleted= 0;
assert( new_table) ;
/* We don't want update TIMESTAMP fields during ALTER Table. */ table-> timestamp_ field_type= TIMESTAMP_ NO_AUTO_ SET; table-> next_number_ field= new_table- >found_ next_number_ field; between_ tables( table,
new_table,
alter_ info->create_ list,
ignore,
order_ num,
order,
&copied,
&deleted,
alter_ info->keys_ onoff,
alter_ info->error_ if_not_ empty);
new_
new_
error= copy_data_
/* We must not ignore bad input! */ >count_ cuted_fields= CHECK_FIELD_ ERROR_FOR_ NULL;
session-
if (table- >s->tmp_ table != STANDARD_TABLE)
{
/* We changed a temporary table */
if (error)
goto err1;
/* Close lock if this is a transactional table */
mysql_ unlock_ tables( session, session->lock);
session- >lock= 0;
if (session->lock)
{
}
/* Remove link to old table and rename the new one */ >close_ temporary_ table(table) ;
session-
/* Should pass the 'new_name' as we store table name in the cache */ tifier alter_identifie r(new_db, new_name); >renameAlterTem poraryTable( alter_identifie r))
new_table- >intern_ close_table( );
free(new_ table);
TableIden
if (new_table-
goto err1;
}
else
{
if (new_table)
{
/*
Close the intermediate table that will be the new table.
Note that MERGE tables do not have their children attached here.
*/
}
pthread_ mutex_lock( &LOCK_open) ; /* ALTER TABLE */
if (error)
TableIdentifie r identifier(new_db, tmp_name, INTERNAL_ TMP_TABLE) ;
quick_ rm_table( *session, identifier);
pthread_ mutex_unlock( &LOCK_open) ;
{
goto err;
}
/* tables( )
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_
call to remove name-locks from table cache and list of open table.
*/
session- >set_proc_ info("rename result table");
snprintf( old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session- >thread_ id);
my_ casedn_ str(files_ charset_ info, old_name);
wait_ while_table_ is_used( session, table, HA_EXTRA_ PREPARE_ FOR_RENAME) ; >close_ data_files_ and_morph_ locks(db, table_name);
session-
error= 0; old_db_ type= old_db_type;
save_
/*
mysql_ rename_ table() , because we just juggle with the FRM and nothing
compare_ table() . Then, we need one additional call to rename_ table(old_ db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
TableIdentifie r identifier(new_db, tmp_name, INTERNAL_ TMP_TABLE) ;
quick_ rm_table( *session, identifier); rename_ table(new_ db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
This leads to the storage engine (SE) not being notified for renames in
more. If we have an intermediate table, then we notify the SE that
it should become the actual table. Later, we will recycle the old table.
However, in case of ALTER Table RENAME there might be no intermediate
table. This is when the old and new tables are compatible, according to
*/
if (mysql_
{
error= 1;
}
else
{
if (mysql_
{
/* Try to get everything back. */
error= 1;
}
}
if (error)
session- >unlink_ open_table( table);
session- >unlink_ open_table( name_lock) ;
pthread_ mutex_unlock( &LOCK_open) ;
{
/*
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.
*/
if (name_lock)
return true;
}
{
TableIdentifie r old_identifier(db, old_name, INTERNAL_ TMP_TABLE) ;
quick_ rm_table( *session, old_identifier);
}
pthread_ mutex_unlock( &LOCK_open) ;
session- >set_proc_ info("end" );
write_ bin_log( session, session- >query. c_str() ); list->table= NULL;
table_
}
/* area::is_ set() will fail an assert. >is_error( )) tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
(ulong) session- >cuted_ fields) ; >my_ok( copied + deleted, 0, 0L, tmp_name); >some_tables_ deleted= 0;
* Field::store() may have called my_error(). If this is
* the case, we must not send an ok packet, since
* Diagnostics_
*/
if (! session-
{
snprintf(
session-
session-
return false;
}
else
{
/* my_error() was called. Return true (which means error...) */
return true;
}