67
enum enum_enable_or_disable keys_onoff,
67
message::AlterTable &alter_table_message,
68
68
bool error_if_not_empty);
70
70
static bool prepare_alter_table(Session *session,
72
HA_CREATE_INFO *create_info,
73
const message::Table &original_proto,
74
message::Table &table_message,
75
AlterInfo *alter_info);
72
HA_CREATE_INFO *create_info,
73
const message::Table &original_proto,
74
message::Table &table_message,
75
message::AlterTable &alter_table_message,
76
AlterInfo *alter_info);
77
78
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
80
static int apply_online_alter_keys_onoff(Session *session,
82
const message::AlterTable::AlterKeysOnOff &op);
84
static int apply_online_rename_table(Session *session,
86
plugin::StorageEngine *original_engine,
87
identifier::Table &original_table_identifier,
88
identifier::Table &new_table_identifier,
89
const message::AlterTable::RenameTable &alter_operation);
79
91
namespace statement {
81
AlterTable::AlterTable(Session *in_session, Table_ident *, drizzled::ha_build_method build_arg) :
93
AlterTable::AlterTable(Session *in_session, Table_ident *) :
82
94
CreateTable(in_session)
84
96
set_command(SQLCOM_ALTER_TABLE);
85
alter_info.build_method= build_arg;
88
99
} // namespace statement
247
258
HA_CREATE_INFO *create_info,
248
259
const message::Table &original_proto,
249
260
message::Table &table_message,
261
message::AlterTable &alter_table_message,
250
262
AlterInfo *alter_info)
252
264
uint32_t used_fields= create_info->used_fields;
265
vector<string> drop_keys;
266
vector<string> drop_columns;
267
vector<string> drop_fkeys;
269
/* we use drop_(keys|columns|fkey) below to check that we can do all
270
operations we've been asked to do */
271
for (int operationnr= 0; operationnr < alter_table_message.operations_size();
274
const message::AlterTable::AlterTableOperation &operation=
275
alter_table_message.operations(operationnr);
277
switch (operation.operation())
279
case message::AlterTable::AlterTableOperation::DROP_KEY:
280
drop_keys.push_back(operation.drop_name());
282
case message::AlterTable::AlterTableOperation::DROP_COLUMN:
283
drop_columns.push_back(operation.drop_name());
285
case message::AlterTable::AlterTableOperation::DROP_FOREIGN_KEY:
286
drop_fkeys.push_back(operation.drop_name());
254
293
/* Let new create options override the old ones */
255
294
message::Table::TableOptions *table_options= table_message.mutable_options();
275
314
for (Field **f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
277
316
/* Check if field should be dropped */
278
AlterInfo::drop_list_t::iterator drop(alter_info->drop_list.begin());
279
for (; drop != alter_info->drop_list.end(); drop++)
317
vector<string>::iterator it= drop_columns.begin();
318
while ((it != drop_columns.end()))
281
if (drop->type == AlterDrop::COLUMN &&
282
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
320
if (! my_strcasecmp(system_charset_info, field->field_name, (*it).c_str()))
284
322
/* Reset auto_increment value if it was dropped */
285
323
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
428
466
for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
430
468
char *key_name= key_info->name;
431
AlterInfo::drop_list_t::iterator drop(alter_info->drop_list.begin());
432
for (; drop != alter_info->drop_list.end(); drop++)
470
vector<string>::iterator it= drop_keys.begin();
471
while ((it != drop_keys.end()))
434
if (drop->type == AlterDrop::KEY &&
435
not my_strcasecmp(system_charset_info, key_name, drop->name))
473
if (! my_strcasecmp(system_charset_info, key_name, (*it).c_str()))
439
if (drop != alter_info->drop_list.end())
478
if (it != drop_keys.end())
441
alter_info->drop_list.erase(drop);
532
571
/* Copy over existing foreign keys */
533
572
for (int32_t j= 0; j < original_proto.fk_constraint_size(); j++)
535
AlterInfo::drop_list_t::iterator drop(alter_info->drop_list.begin());
536
for (; drop != alter_info->drop_list.end(); drop++)
574
vector<string>::iterator it= drop_fkeys.begin();
575
while ((it != drop_fkeys.end()))
538
if (drop->type == AlterDrop::FOREIGN_KEY &&
539
not my_strcasecmp(system_charset_info, original_proto.fk_constraint(j).name().c_str(), drop->name))
577
if (! my_strcasecmp(system_charset_info, original_proto.fk_constraint(j).name().c_str(), (*it).c_str()))
544
if (drop != alter_info->drop_list.end())
584
if (it != drop_fkeys.end())
546
alter_info->drop_list.erase(drop);
586
drop_fkeys.erase(it);
742
800
static bool alter_table_manage_keys(Session *session,
743
801
Table *table, int indexes_were_disabled,
744
enum enum_enable_or_disable keys_onoff)
802
const message::AlterTable &alter_table_message)
747
switch (keys_onoff) {
805
if (alter_table_message.has_alter_keys_onoff()
806
&& alter_table_message.alter_keys_onoff().enable())
749
808
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
752
if (not indexes_were_disabled)
754
/* fall-through: disabled indexes */
811
if ((! alter_table_message.has_alter_keys_onoff() && indexes_were_disabled)
812
|| (alter_table_message.has_alter_keys_onoff()
813
&& ! alter_table_message.alter_keys_onoff().enable()))
756
815
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
939
1008
tmp.reset(ALTER_KEYS_ONOFF);
940
1009
tmp&= alter_info->flags;
942
if (not (tmp.any()) && not table->getShare()->getType()) // no need to touch frm
1011
if((not (tmp.any()) && not table->getShare()->getType())) // no need to touch frm
944
switch (alter_info->keys_onoff)
951
wait_while_table_is_used() ensures that table being altered is
952
opened only by this thread and that Table::TableShare::version
953
of Table object corresponding to this table is 0.
954
The latter guarantees that no DML statement will open this table
955
until ALTER Table finishes (i.e. until close_thread_tables())
956
while the fact that the table is still open gives us protection
957
from concurrent DDL statements.
960
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
961
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
963
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
965
/* COND_refresh will be signaled in close_thread_tables() */
970
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
971
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
973
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
975
/* COND_refresh will be signaled in close_thread_tables() */
979
if (error == HA_ERR_WRONG_COMMAND)
982
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
983
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
987
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
989
Unlike to the above case close_cached_table() below will remove ALL
990
instances of Table from table cache (it will also remove table lock
991
held by this thread). So to make actual table renaming and writing
992
to binlog atomic we have to put them into the same critical section
993
protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
994
access() and rename_table() calls.
997
if (not error && not (original_table_identifier == new_table_identifier))
999
session->set_proc_info("rename");
1001
Then do a 'simple' rename of the table. First we need to close all
1002
instances of 'source' table.
1004
session->close_cached_table(table);
1006
Then, we want check once again that target table does not exist.
1007
Actually the order of these two steps does not matter since
1008
earlier we took name-lock on the target table, so we do them
1009
in this particular order only to be consistent with 5.0, in which
1010
we don't take this name-lock and where this order really matters.
1011
@todo Investigate if we need this access() check at all.
1013
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1015
my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1020
if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1027
if (error == HA_ERR_WRONG_COMMAND)
1030
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1031
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1013
if (alter_table_message.has_alter_keys_onoff())
1015
error= apply_online_alter_keys_onoff(session, table,
1016
alter_table_message.alter_keys_onoff());
1018
if (error == HA_ERR_WRONG_COMMAND)
1021
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1022
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1027
if (alter_table_message.has_rename())
1029
error= apply_online_rename_table(session,
1032
original_table_identifier,
1033
new_table_identifier,
1034
alter_table_message.rename());
1036
if (error == HA_ERR_WRONG_COMMAND)
1039
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1040
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1065
if (alter_table_message.build_method() == message::AlterTable::BUILD_ONLINE)
1067
my_error(*session->getQueryString(), ER_NOT_SUPPORTED_YET);
1055
1071
/* We have to do full alter table. */
1056
1072
new_engine= create_info->db_type;
1058
if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1074
if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_table_message, alter_info))
1063
1079
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
1065
alter_info->build_method= HA_BUILD_OFFLINE;
1067
1081
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1069
1083
/* Create a temporary table with the new format */
1349
static int apply_online_alter_keys_onoff(Session *session,
1351
const message::AlterTable::AlterKeysOnOff &op)
1358
wait_while_table_is_used() ensures that table being altered is
1359
opened only by this thread and that Table::TableShare::version
1360
of Table object corresponding to this table is 0.
1361
The latter guarantees that no DML statement will open this table
1362
until ALTER Table finishes (i.e. until close_thread_tables())
1363
while the fact that the table is still open gives us protection
1364
from concurrent DDL statements.
1367
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1368
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1370
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1372
/* COND_refresh will be signaled in close_thread_tables() */
1377
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1378
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1380
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1382
/* COND_refresh will be signaled in close_thread_tables() */
1388
static int apply_online_rename_table(Session *session,
1390
plugin::StorageEngine *original_engine,
1391
identifier::Table &original_table_identifier,
1392
identifier::Table &new_table_identifier,
1393
const message::AlterTable::RenameTable &alter_operation)
1397
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
1399
Unlike to the above case close_cached_table() below will remove ALL
1400
instances of Table from table cache (it will also remove table lock
1401
held by this thread). So to make actual table renaming and writing
1402
to binlog atomic we have to put them into the same critical section
1403
protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
1404
access() and rename_table() calls.
1407
if (not (original_table_identifier == new_table_identifier))
1409
assert(alter_operation.to_name() == new_table_identifier.getTableName());
1410
assert(alter_operation.to_schema() == new_table_identifier.getSchemaName());
1412
session->set_proc_info("rename");
1414
Then do a 'simple' rename of the table. First we need to close all
1415
instances of 'source' table.
1417
session->close_cached_table(table);
1419
Then, we want check once again that target table does not exist.
1420
Actually the order of these two steps does not matter since
1421
earlier we took name-lock on the target table, so we do them
1422
in this particular order only to be consistent with 5.0, in which
1423
we don't take this name-lock and where this order really matters.
1424
@todo Investigate if we need this access() check at all.
1426
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1428
my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
1433
if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1335
1442
bool alter_table(Session *session,
1336
1443
identifier::Table &original_table_identifier,
1337
1444
identifier::Table &new_table_identifier,
1350
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1456
message::AlterTable *alter_table_message= session->lex().alter_table();
1458
alter_table_message->set_catalog(original_table_identifier.getCatalogName());
1459
alter_table_message->set_schema(original_table_identifier.getSchemaName());
1460
alter_table_message->set_name(original_table_identifier.getTableName());
1462
if (alter_table_message->operations_size()
1463
&& (alter_table_message->operations(0).operation()
1464
== message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE
1465
|| alter_table_message->operations(0).operation()
1466
== message::AlterTable::AlterTableOperation::IMPORT_TABLESPACE))
1468
bool discard= (alter_table_message->operations(0).operation() ==
1469
message::AlterTable::AlterTableOperation::DISCARD_TABLESPACE);
1352
1470
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1353
return discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1471
return discard_or_import_tablespace(session, table_list, discard);
1356
1474
session->set_proc_info("init");