2013-04-17 06:02:12 +02:00
|
|
|
#if TOKU_INCLUDE_ALTER_56
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
#include "ha_tokudb_alter_common.cc"
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
void
|
|
|
|
ha_tokudb::print_alter_info(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
|
|
|
printf("***are keys of two tables same? %d\n", tables_have_same_keys(table, altered_table, false, false));
|
|
|
|
if (ha_alter_info->handler_flags) {
|
|
|
|
printf("***alter flags set ***\n");
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
if (ha_alter_info->handler_flags & (1 << i))
|
|
|
|
printf("%d\n", i);
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// everyone calculates data by doing some default_values - record[0], but I do not see why
|
|
|
|
// that is necessary
|
|
|
|
printf("******\n");
|
|
|
|
printf("***orig table***\n");
|
2013-04-17 06:02:11 +02:00
|
|
|
for (uint i = 0; i < table->s->fields; i++) {
|
2013-04-17 06:02:12 +02:00
|
|
|
//
|
|
|
|
// make sure to use table->field, and NOT table->s->field
|
|
|
|
//
|
|
|
|
Field* curr_field = table->field[i];
|
|
|
|
uint null_offset = get_null_offset(table, curr_field);
|
|
|
|
printf(
|
|
|
|
"name: %s, nullable: %d, null_offset: %d, is_null_field: %d, is_null %d, \n",
|
|
|
|
curr_field->field_name,
|
|
|
|
curr_field->null_bit,
|
|
|
|
null_offset,
|
2013-04-17 06:02:13 +02:00
|
|
|
curr_field->real_maybe_null(),
|
|
|
|
curr_field->real_maybe_null() ? table->s->default_values[null_offset] & curr_field->null_bit : 0xffffffff
|
2013-04-17 06:02:12 +02:00
|
|
|
);
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
printf("******\n");
|
|
|
|
printf("***altered table***\n");
|
|
|
|
for (uint i = 0; i < altered_table->s->fields; i++) {
|
|
|
|
Field* curr_field = altered_table->field[i];
|
|
|
|
uint null_offset = get_null_offset(altered_table, curr_field);
|
|
|
|
printf(
|
|
|
|
"name: %s, nullable: %d, null_offset: %d, is_null_field: %d, is_null %d, \n",
|
|
|
|
curr_field->field_name,
|
|
|
|
curr_field->null_bit,
|
|
|
|
null_offset,
|
2013-04-17 06:02:13 +02:00
|
|
|
curr_field->real_maybe_null(),
|
|
|
|
curr_field->real_maybe_null() ? altered_table->s->default_values[null_offset] & curr_field->null_bit : 0xffffffff
|
2013-04-17 06:02:12 +02:00
|
|
|
);
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
printf("******\n");
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// workaround for fill_alter_inplace_info bug (#5193)
|
|
|
|
// the function erroneously sets the ADD_INDEX and DROP_INDEX flags for a column addition that does not
|
|
|
|
// change the keys. the following code turns the ADD_INDEX and DROP_INDEX flags so that we can do hot
|
|
|
|
// column addition later.
|
|
|
|
static ulong
|
|
|
|
fix_handler_flags(Alter_inplace_info *ha_alter_info, TABLE *table, TABLE *altered_table) {
|
|
|
|
ulong handler_flags = ha_alter_info->handler_flags;
|
|
|
|
if ((handler_flags & (Alter_inplace_info::ADD_COLUMN + Alter_inplace_info::DROP_COLUMN)) != 0) {
|
|
|
|
if ((handler_flags & (Alter_inplace_info::ADD_INDEX + Alter_inplace_info::DROP_INDEX)) != 0) {
|
|
|
|
if (tables_have_same_keys(table, altered_table, false, false)) {
|
|
|
|
handler_flags &= ~(Alter_inplace_info::ADD_INDEX + Alter_inplace_info::DROP_INDEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return handler_flags;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
// require that there is no intersection of add and drop names.
|
|
|
|
static bool
|
|
|
|
is_disjoint_add_drop(Alter_inplace_info *ha_alter_info) {
|
|
|
|
for (uint d = 0; d < ha_alter_info->index_drop_count; d++) {
|
|
|
|
KEY *drop_key = ha_alter_info->index_drop_buffer[d];
|
|
|
|
for (uint a = 0; a < ha_alter_info->index_add_count; a++) {
|
|
|
|
KEY *add_key = &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[a]];
|
|
|
|
if (strcmp(drop_key->name, add_key->name) == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
#if 50600 < MYSQL_VERSION_ID
|
|
|
|
#define TOKU_ALTER_RENAME ALTER_RENAME
|
|
|
|
#elif 50500 < MYSQL_VERSION_ID
|
|
|
|
#define TOKU_ALTER_RENAME ALTER_RENAME_56
|
|
|
|
#else
|
|
|
|
#error
|
|
|
|
#endif
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
class tokudb_alter_ctx : public inplace_alter_handler_ctx {
|
|
|
|
public:
|
|
|
|
tokudb_alter_ctx() {
|
2013-04-17 06:02:13 +02:00
|
|
|
alter_txn = NULL;
|
2013-04-17 06:02:13 +02:00
|
|
|
add_index_changed = false;
|
|
|
|
drop_index_changed = false;
|
|
|
|
compression_changed = false;
|
|
|
|
}
|
|
|
|
public:
|
2013-04-17 06:02:13 +02:00
|
|
|
DB_TXN *alter_txn;
|
2013-04-17 06:02:13 +02:00
|
|
|
bool add_index_changed;
|
|
|
|
bool incremented_num_DBs, modified_DBs;
|
|
|
|
bool drop_index_changed;
|
|
|
|
bool compression_changed;
|
|
|
|
enum toku_compression_method orig_compression_method;
|
|
|
|
};
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// true if some bit in mask is set and no bit in ~mask is set
|
|
|
|
// otherwise false
|
|
|
|
static bool
|
2013-04-17 06:02:12 +02:00
|
|
|
only_flags(ulong bits, ulong mask) {
|
2013-04-17 06:02:12 +02:00
|
|
|
return (bits & mask) != 0 && (bits & ~mask) == 0;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
// Check if an alter table operation on this table and described by the alter table parameters is supported inplace
|
|
|
|
// and if so, what type of locking is needed to execute it.
|
|
|
|
// return values:
|
|
|
|
// HA_ALTER_INPLACE_NOT_SUPPORTED: alter operation is not supported as an inplace operation, a table copy is required
|
|
|
|
// HA_ALTER_ERROR: the alter table operation should fail
|
|
|
|
// HA_ALTER_INPLACE_SHARED_LOCK: prepare and alter methods called with MDL SNW, concurrent reads, no writes
|
|
|
|
// HA_ALTER_INPLACE_NO_LOCK: prepare and alter methods called with MDL SW, concurrent reads, writes.
|
|
|
|
// must set WRITE_ALLOW_WRITE lock type in the external lock method to avoid deadlocks
|
|
|
|
// with the MDL lock and the table lock
|
|
|
|
// HA_ALTER_INPLACE_EXCLUSIVE_LOCK: the alter operation requires an exclusive MDL no concurrent reads, no writes
|
2013-04-17 06:02:11 +02:00
|
|
|
enum_alter_inplace_result
|
|
|
|
ha_tokudb::check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
|
|
|
TOKUDB_DBUG_ENTER("check_if_supported_alter");
|
|
|
|
|
|
|
|
if (tokudb_debug & TOKUDB_DEBUG_ALTER_TABLE_INFO) {
|
|
|
|
print_alter_info(altered_table, ha_alter_info);
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
THD *thd = ha_thd();
|
2013-04-17 06:02:11 +02:00
|
|
|
enum_alter_inplace_result result = HA_ALTER_INPLACE_NOT_SUPPORTED; // default is NOT inplace
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
ulong handler_flags = fix_handler_flags(ha_alter_info, table, altered_table);
|
2013-04-17 06:02:12 +02:00
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
// always allow rename table + any other operation, so turn off the handler flag
|
|
|
|
if (handler_flags & Alter_inplace_info::TOKU_ALTER_RENAME) {
|
|
|
|
handler_flags &= ~Alter_inplace_info::TOKU_ALTER_RENAME;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// add/drop index
|
|
|
|
if (only_flags(handler_flags, Alter_inplace_info::DROP_INDEX + Alter_inplace_info::DROP_UNIQUE_INDEX +
|
|
|
|
Alter_inplace_info::ADD_INDEX + Alter_inplace_info::ADD_UNIQUE_INDEX)) {
|
|
|
|
if ((ha_alter_info->index_add_count > 0 || ha_alter_info->index_drop_count > 0) &&
|
2013-04-17 06:02:13 +02:00
|
|
|
!tables_have_same_keys(table, altered_table, false, false) &&
|
|
|
|
is_disjoint_add_drop(ha_alter_info)) {
|
2013-04-17 06:02:12 +02:00
|
|
|
|
|
|
|
result = HA_ALTER_INPLACE_SHARED_LOCK;
|
|
|
|
|
|
|
|
// someday, allow multiple hot indexes via alter table add key. don't forget to change the store_lock function.
|
|
|
|
// for now, hot indexing is only supported via session variable with the create index sql command
|
|
|
|
if (ha_alter_info->index_add_count == 1 && ha_alter_info->index_drop_count == 0 &&
|
|
|
|
get_create_index_online(thd) && thd_sql_command(thd) == SQLCOM_CREATE_INDEX) {
|
2013-04-17 06:02:13 +02:00
|
|
|
// external_lock set WRITE_ALLOW_WRITE which allows writes concurrent with the index creation
|
|
|
|
result = HA_ALTER_INPLACE_NO_LOCK;
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
2013-04-17 06:02:13 +02:00
|
|
|
// column default
|
|
|
|
if (only_flags(handler_flags, Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
|
2013-04-17 06:02:13 +02:00
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
2013-04-17 06:02:13 +02:00
|
|
|
} else
|
2013-04-17 06:02:11 +02:00
|
|
|
// column rename
|
2013-04-17 06:02:12 +02:00
|
|
|
if (only_flags(handler_flags, Alter_inplace_info::ALTER_COLUMN_NAME + Alter_inplace_info::ALTER_COLUMN_DEFAULT)) {
|
2013-04-17 06:02:11 +02:00
|
|
|
// we have identified a possible column rename,
|
|
|
|
// but let's do some more checks
|
|
|
|
|
|
|
|
// we will only allow an hcr if there are no changes
|
2013-04-17 06:02:12 +02:00
|
|
|
// in column positions (ALTER_COLUMN_ORDER is not set)
|
|
|
|
|
|
|
|
// now need to verify that one and only one column
|
|
|
|
// has changed only its name. If we find anything to
|
|
|
|
// the contrary, we don't allow it, also check indexes
|
2013-04-17 06:02:12 +02:00
|
|
|
bool cr_supported = column_rename_supported(table, altered_table, (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_ORDER) != 0);
|
2013-04-17 06:02:12 +02:00
|
|
|
if (cr_supported)
|
2013-04-17 06:02:13 +02:00
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
2013-04-17 06:02:12 +02:00
|
|
|
} else
|
2013-04-17 06:02:12 +02:00
|
|
|
// add column
|
2013-04-17 06:02:12 +02:00
|
|
|
if (only_flags(handler_flags, Alter_inplace_info::ADD_COLUMN + Alter_inplace_info::ALTER_COLUMN_ORDER)) {
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t added_columns[altered_table->s->fields];
|
|
|
|
uint32_t num_added_columns = 0;
|
2013-04-17 06:02:11 +02:00
|
|
|
int r = find_changed_columns(added_columns, &num_added_columns, table, altered_table);
|
|
|
|
if (r == 0) {
|
|
|
|
if (tokudb_debug & TOKUDB_DEBUG_ALTER_TABLE_INFO) {
|
2013-04-17 06:02:13 +02:00
|
|
|
for (uint32_t i = 0; i < num_added_columns; i++) {
|
|
|
|
uint32_t curr_added_index = added_columns[i];
|
2013-04-17 06:02:11 +02:00
|
|
|
Field* curr_added_field = altered_table->field[curr_added_index];
|
|
|
|
printf("Added column: index %d, name %s\n", curr_added_index, curr_added_field->field_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
|
|
|
}
|
|
|
|
} else
|
2013-04-17 06:02:12 +02:00
|
|
|
// drop column
|
2013-04-17 06:02:12 +02:00
|
|
|
if (only_flags(handler_flags, Alter_inplace_info::DROP_COLUMN + Alter_inplace_info::ALTER_COLUMN_ORDER)) {
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t dropped_columns[table->s->fields];
|
|
|
|
uint32_t num_dropped_columns = 0;
|
2013-04-17 06:02:11 +02:00
|
|
|
int r = find_changed_columns(dropped_columns, &num_dropped_columns, altered_table, table);
|
|
|
|
if (r == 0) {
|
|
|
|
if (tokudb_debug & TOKUDB_DEBUG_ALTER_TABLE_INFO) {
|
2013-04-17 06:02:13 +02:00
|
|
|
for (uint32_t i = 0; i < num_dropped_columns; i++) {
|
|
|
|
uint32_t curr_dropped_index = dropped_columns[i];
|
2013-04-17 06:02:11 +02:00
|
|
|
Field* curr_dropped_field = table->field[curr_dropped_index];
|
|
|
|
printf("Dropped column: index %d, name %s\n", curr_dropped_index, curr_dropped_field->field_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
|
|
|
}
|
2013-04-17 06:02:13 +02:00
|
|
|
}
|
|
|
|
#ifndef MARIADB_BASE_VERSION
|
|
|
|
else if (only_flags(handler_flags, Alter_inplace_info::CHANGE_CREATE_OPTION)) {
|
|
|
|
HA_CREATE_INFO *create_info = ha_alter_info->create_info;
|
2013-04-17 06:02:12 +02:00
|
|
|
// alter auto_increment
|
|
|
|
if (only_flags(create_info->used_fields, HA_CREATE_USED_AUTO)) {
|
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
|
|
|
} else
|
|
|
|
// alter row_format
|
|
|
|
if (only_flags(create_info->used_fields, HA_CREATE_USED_ROW_FORMAT)) {
|
|
|
|
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 06:02:13 +02:00
|
|
|
#endif
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// turn not supported into error if the slow alter table (copy) is disabled
|
2013-04-17 06:02:11 +02:00
|
|
|
if (result == HA_ALTER_INPLACE_NOT_SUPPORTED && get_disable_slow_alter(thd)) {
|
|
|
|
print_error(HA_ERR_UNSUPPORTED, MYF(0));
|
|
|
|
result = HA_ALTER_ERROR;
|
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ha_tokudb::prepare_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
|
|
|
TOKUDB_DBUG_ENTER("prepare_inplace_alter_table");
|
2013-04-17 06:02:12 +02:00
|
|
|
bool result = false; // success
|
2013-04-17 06:02:13 +02:00
|
|
|
|
|
|
|
assert(ha_alter_info->handler_ctx == NULL);
|
|
|
|
tokudb_alter_ctx *ctx = new tokudb_alter_ctx;
|
|
|
|
assert(ctx);
|
|
|
|
ha_alter_info->handler_ctx = ctx;
|
2013-04-17 06:02:13 +02:00
|
|
|
ctx->alter_txn = transaction;
|
2013-04-17 06:02:11 +02:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ha_tokudb::inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
|
|
|
TOKUDB_DBUG_ENTER("inplace_alter_table");
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
int error = 0;
|
2013-04-17 06:02:13 +02:00
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
2013-04-17 06:02:12 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
HA_CREATE_INFO *create_info = ha_alter_info->create_info;
|
2013-04-17 06:02:12 +02:00
|
|
|
ulong handler_flags = fix_handler_flags(ha_alter_info, table, altered_table);
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error == 0 && (handler_flags & (Alter_inplace_info::DROP_INDEX + Alter_inplace_info::DROP_UNIQUE_INDEX))) {
|
2013-04-17 06:02:11 +02:00
|
|
|
error = alter_table_drop_index(altered_table, ha_alter_info);
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error == 0 && (handler_flags & (Alter_inplace_info::ADD_INDEX + Alter_inplace_info::ADD_UNIQUE_INDEX))) {
|
|
|
|
error = alter_table_add_index(altered_table, ha_alter_info);
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error == 0 && (handler_flags & (Alter_inplace_info::ADD_COLUMN + Alter_inplace_info::DROP_COLUMN))) {
|
2013-04-17 06:02:12 +02:00
|
|
|
error = alter_table_add_or_drop_column(altered_table, ha_alter_info);
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error == 0 && (handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) && (create_info->used_fields & HA_CREATE_USED_AUTO)) {
|
2013-04-17 06:02:13 +02:00
|
|
|
error = write_auto_inc_create(share->status_block, create_info->auto_increment_value, ctx->alter_txn);
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error == 0 && (handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) && (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT)) {
|
2013-04-17 06:02:12 +02:00
|
|
|
// Get the current type
|
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
|
|
|
DB *db = share->key_file[0];
|
|
|
|
error = db->get_compression_method(db, &ctx->orig_compression_method);
|
|
|
|
assert(error == 0);
|
2013-04-17 06:02:13 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// Set the new type.
|
2013-04-17 06:02:13 +02:00
|
|
|
enum toku_compression_method method = row_type_to_compression_method(create_info->row_type);
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t curr_num_DBs = table->s->keys + test(hidden_primary_key);
|
|
|
|
for (uint32_t i = 0; i < curr_num_DBs; i++) {
|
2013-04-17 06:02:12 +02:00
|
|
|
db = share->key_file[i];
|
2013-04-17 06:02:12 +02:00
|
|
|
error = db->change_compression_method(db, method);
|
2013-04-17 06:02:12 +02:00
|
|
|
if (error)
|
2013-04-17 06:02:12 +02:00
|
|
|
break;
|
2013-04-17 06:02:13 +02:00
|
|
|
ctx->compression_changed = true;
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool result = false; // success
|
|
|
|
if (error) {
|
|
|
|
print_error(error, MYF(0));
|
|
|
|
result = true; // failure
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ha_tokudb::alter_table_add_index(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
// sort keys in add index order
|
2013-04-17 06:02:11 +02:00
|
|
|
KEY *key_info = (KEY*) my_malloc(sizeof (KEY) * ha_alter_info->index_add_count, MYF(MY_WME));
|
|
|
|
for (uint i = 0; i < ha_alter_info->index_add_count; i++) {
|
2013-04-17 06:02:12 +02:00
|
|
|
KEY *key = &key_info[i];
|
2013-04-17 06:02:11 +02:00
|
|
|
*key = ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]];
|
|
|
|
for (KEY_PART_INFO *key_part= key->key_part; key_part < key->key_part + key->key_parts; key_part++)
|
|
|
|
key_part->field = table->field[key_part->fieldnr];
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
|
|
|
ctx->add_index_changed = true;
|
2013-04-17 06:02:13 +02:00
|
|
|
int error = tokudb_add_index(table, key_info, ha_alter_info->index_add_count, ctx->alter_txn, &ctx->incremented_num_DBs, &ctx->modified_DBs);
|
2013-04-17 06:02:11 +02:00
|
|
|
if (error == HA_ERR_FOUND_DUPP_KEY) {
|
|
|
|
// hack for now, in case of duplicate key error,
|
|
|
|
// because at the moment we cannot display the right key
|
|
|
|
// information to the user, so that he knows potentially what went
|
|
|
|
// wrong.
|
|
|
|
last_dup_key = MAX_KEY;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
my_free(key_info);
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
return error;
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
static bool find_index_of_key(const char *key_name, TABLE *table, uint *index_offset_ptr) {
|
|
|
|
for (uint i = 0; i < table->s->keys; i++) {
|
|
|
|
if (strcmp(key_name, table->key_info[i].name) == 0) {
|
|
|
|
*index_offset_ptr = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool find_index_of_key(const char *key_name, KEY *key_info, uint key_count, uint *index_offset_ptr) {
|
|
|
|
for (uint i = 0; i < key_count; i++) {
|
|
|
|
if (strcmp(key_name, key_info[i].name) == 0) {
|
|
|
|
*index_offset_ptr = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
int
|
|
|
|
ha_tokudb::alter_table_drop_index(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
2013-04-17 06:02:13 +02:00
|
|
|
KEY *key_info = table->key_info;
|
|
|
|
// translate key names to indexes into the key_info array
|
2013-04-17 06:02:11 +02:00
|
|
|
uint index_drop_offsets[ha_alter_info->index_drop_count];
|
2013-04-17 06:02:13 +02:00
|
|
|
for (uint i = 0; i < ha_alter_info->index_drop_count; i++) {
|
|
|
|
bool found;
|
|
|
|
found = find_index_of_key(ha_alter_info->index_drop_buffer[i]->name, table, &index_drop_offsets[i]);
|
|
|
|
if (!found) {
|
|
|
|
// undo of add key in partition engine
|
|
|
|
found = find_index_of_key(ha_alter_info->index_drop_buffer[i]->name, ha_alter_info->key_info_buffer, ha_alter_info->key_count, &index_drop_offsets[i]);
|
|
|
|
assert(found);
|
|
|
|
key_info = ha_alter_info->key_info_buffer;
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
|
|
|
|
// drop indexes
|
2013-04-17 06:02:12 +02:00
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
|
|
|
ctx->drop_index_changed = true;
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
int error = drop_indexes(table, index_drop_offsets, ha_alter_info->index_drop_count, key_info, ctx->alter_txn);
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
return error;
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ha_tokudb::alter_table_add_or_drop_column(TABLE *altered_table, Alter_inplace_info *ha_alter_info) {
|
2013-04-17 06:02:13 +02:00
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
2013-04-17 06:02:11 +02:00
|
|
|
int error;
|
|
|
|
uchar *column_extra = NULL;
|
|
|
|
uchar *row_desc_buff = NULL;
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t max_new_desc_size = 0;
|
|
|
|
uint32_t max_column_extra_size;
|
|
|
|
uint32_t num_column_extra;
|
|
|
|
uint32_t num_columns = 0;
|
|
|
|
uint32_t curr_num_DBs = table->s->keys + test(hidden_primary_key);
|
2013-04-17 06:02:11 +02:00
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t columns[table->s->fields + altered_table->s->fields]; // set size such that we know it is big enough for both cases
|
2013-04-17 06:02:11 +02:00
|
|
|
memset(columns, 0, sizeof(columns));
|
|
|
|
|
|
|
|
KEY_AND_COL_INFO altered_kc_info;
|
|
|
|
memset(&altered_kc_info, 0, sizeof(altered_kc_info));
|
|
|
|
|
|
|
|
error = allocate_key_and_col_info(altered_table->s, &altered_kc_info);
|
|
|
|
if (error) { goto cleanup; }
|
|
|
|
|
|
|
|
max_new_desc_size = get_max_desc_size(&altered_kc_info, altered_table);
|
|
|
|
row_desc_buff = (uchar *)my_malloc(max_new_desc_size, MYF(MY_WME));
|
|
|
|
if (row_desc_buff == NULL){ error = ENOMEM; goto cleanup;}
|
|
|
|
|
|
|
|
error = initialize_key_and_col_info(
|
|
|
|
altered_table->s,
|
|
|
|
altered_table,
|
|
|
|
&altered_kc_info,
|
|
|
|
hidden_primary_key,
|
|
|
|
primary_key
|
|
|
|
);
|
|
|
|
if (error) { goto cleanup; }
|
|
|
|
|
|
|
|
// generate the array of columns
|
|
|
|
if (ha_alter_info->handler_flags & Alter_inplace_info::DROP_COLUMN) {
|
|
|
|
find_changed_columns(
|
|
|
|
columns,
|
|
|
|
&num_columns,
|
|
|
|
altered_table,
|
|
|
|
table
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN) {
|
|
|
|
find_changed_columns(
|
|
|
|
columns,
|
|
|
|
&num_columns,
|
|
|
|
table,
|
|
|
|
altered_table
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
assert(0);
|
|
|
|
max_column_extra_size =
|
|
|
|
STATIC_ROW_MUTATOR_SIZE + //max static row_mutator
|
|
|
|
4 + num_columns*(1+1+4+1+1+4) + altered_table->s->reclength + // max dynamic row_mutator
|
|
|
|
(4 + share->kc_info.num_blobs) + // max static blob size
|
|
|
|
(num_columns*(1+4+1+4)); // max dynamic blob size
|
|
|
|
column_extra = (uchar *)my_malloc(max_column_extra_size, MYF(MY_WME));
|
|
|
|
if (column_extra == NULL) { error = ENOMEM; goto cleanup; }
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
for (uint32_t i = 0; i < curr_num_DBs; i++) {
|
2013-04-17 06:02:11 +02:00
|
|
|
DBT row_descriptor;
|
|
|
|
memset(&row_descriptor, 0, sizeof(row_descriptor));
|
|
|
|
KEY* prim_key = (hidden_primary_key) ? NULL : &altered_table->s->key_info[primary_key];
|
|
|
|
KEY* key_info = &altered_table->key_info[i];
|
|
|
|
if (i == primary_key) {
|
|
|
|
row_descriptor.size = create_main_key_descriptor(
|
|
|
|
row_desc_buff,
|
|
|
|
prim_key,
|
|
|
|
hidden_primary_key,
|
|
|
|
primary_key,
|
|
|
|
altered_table,
|
|
|
|
&altered_kc_info
|
|
|
|
);
|
|
|
|
row_descriptor.data = row_desc_buff;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
row_descriptor.size = create_secondary_key_descriptor(
|
|
|
|
row_desc_buff,
|
|
|
|
key_info,
|
|
|
|
prim_key,
|
|
|
|
hidden_primary_key,
|
|
|
|
altered_table,
|
|
|
|
primary_key,
|
|
|
|
i,
|
|
|
|
&altered_kc_info
|
|
|
|
);
|
|
|
|
row_descriptor.data = row_desc_buff;
|
|
|
|
}
|
|
|
|
error = share->key_file[i]->change_descriptor(
|
|
|
|
share->key_file[i],
|
2013-04-17 06:02:13 +02:00
|
|
|
ctx->alter_txn,
|
2013-04-17 06:02:11 +02:00
|
|
|
&row_descriptor,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
if (error) { goto cleanup; }
|
|
|
|
|
|
|
|
if (i == primary_key || table_share->key_info[i].flags & HA_CLUSTERING) {
|
|
|
|
num_column_extra = fill_row_mutator(
|
|
|
|
column_extra,
|
|
|
|
columns,
|
|
|
|
num_columns,
|
|
|
|
altered_table,
|
|
|
|
&altered_kc_info,
|
|
|
|
i,
|
|
|
|
(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN) != 0 // true if adding columns, otherwise is a drop
|
|
|
|
);
|
|
|
|
|
|
|
|
DBT column_dbt;
|
|
|
|
memset(&column_dbt, 0, sizeof column_dbt);
|
|
|
|
column_dbt.data = column_extra;
|
|
|
|
column_dbt.size = num_column_extra;
|
|
|
|
DBUG_ASSERT(num_column_extra <= max_column_extra_size);
|
|
|
|
error = share->key_file[i]->update_broadcast(
|
|
|
|
share->key_file[i],
|
2013-04-17 06:02:13 +02:00
|
|
|
ctx->alter_txn,
|
2013-04-17 06:02:11 +02:00
|
|
|
&column_dbt,
|
|
|
|
DB_IS_RESETTING_OP
|
|
|
|
);
|
|
|
|
if (error) { goto cleanup; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
cleanup:
|
|
|
|
free_key_and_col_info(&altered_kc_info);
|
|
|
|
my_free(row_desc_buff, MYF(MY_ALLOW_ZERO_PTR));
|
|
|
|
my_free(column_extra, MYF(MY_ALLOW_ZERO_PTR));
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ha_tokudb::commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit) {
|
|
|
|
TOKUDB_DBUG_ENTER("commit_inplace_alter_table");
|
2013-04-17 06:02:13 +02:00
|
|
|
|
|
|
|
tokudb_alter_ctx *ctx = static_cast<tokudb_alter_ctx *>(ha_alter_info->handler_ctx);
|
2013-04-17 06:02:11 +02:00
|
|
|
bool result = false; // success
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
if (commit) {
|
2013-04-17 06:02:13 +02:00
|
|
|
if (TOKU_PARTITION_WRITE_FRM_DATA || altered_table->part_info == NULL) {
|
|
|
|
int error = write_frm_data(share->status_block, ctx->alter_txn, altered_table->s->path.str);
|
2013-04-17 06:02:13 +02:00
|
|
|
if (error) {
|
|
|
|
commit = false;
|
|
|
|
result = true;
|
2013-04-17 06:02:11 +02:00
|
|
|
print_error(error, MYF(0));
|
2013-04-17 06:02:13 +02:00
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
if (!commit) {
|
2013-04-17 06:02:13 +02:00
|
|
|
// abort the alter transaction NOW so that any alters are rolled back. this allows the following restores to work.
|
2013-04-17 06:02:13 +02:00
|
|
|
THD *thd = ha_thd();
|
|
|
|
tokudb_trx_data *trx = (tokudb_trx_data *) thd_data_get(thd, tokudb_hton->slot);
|
|
|
|
assert(ctx->alter_txn == trx->stmt);
|
|
|
|
trx->should_abort = true;
|
|
|
|
assert(trx->tokudb_lock_count > 0);
|
|
|
|
if (!--trx->tokudb_lock_count) {
|
|
|
|
abort_txn(ctx->alter_txn);
|
|
|
|
ctx->alter_txn = NULL;
|
|
|
|
trx->stmt = NULL;
|
|
|
|
trx->sub_sp_level = NULL;
|
|
|
|
trx->should_abort = false;
|
|
|
|
}
|
|
|
|
transaction = NULL;
|
2013-04-17 06:02:12 +02:00
|
|
|
|
2013-04-17 06:02:12 +02:00
|
|
|
if (ctx->add_index_changed) {
|
2013-04-17 06:02:11 +02:00
|
|
|
restore_add_index(table, ha_alter_info->index_add_count, ctx->incremented_num_DBs, ctx->modified_DBs);
|
2013-04-17 06:02:12 +02:00
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (ctx->drop_index_changed) {
|
2013-04-17 06:02:13 +02:00
|
|
|
|
2013-04-17 06:02:13 +02:00
|
|
|
// translate key names to indexes into the key_info array
|
2013-04-17 06:02:11 +02:00
|
|
|
uint index_drop_offsets[ha_alter_info->index_drop_count];
|
2013-04-17 06:02:13 +02:00
|
|
|
for (uint i = 0; i < ha_alter_info->index_drop_count; i++) {
|
|
|
|
bool found = find_index_of_key(ha_alter_info->index_drop_buffer[i]->name, table, &index_drop_offsets[i]);
|
|
|
|
assert(found);
|
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
restore_drop_indexes(table, index_drop_offsets, ha_alter_info->index_drop_count);
|
|
|
|
}
|
2013-04-17 06:02:12 +02:00
|
|
|
if (ctx->compression_changed) {
|
2013-04-17 06:02:13 +02:00
|
|
|
uint32_t curr_num_DBs = table->s->keys + test(hidden_primary_key);
|
|
|
|
for (uint32_t i = 0; i < curr_num_DBs; i++) {
|
2013-04-17 06:02:12 +02:00
|
|
|
DB *db = share->key_file[i];
|
|
|
|
int error = db->change_compression_method(db, ctx->orig_compression_method);
|
|
|
|
assert(error == 0);
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 06:02:11 +02:00
|
|
|
}
|
|
|
|
|
2013-04-17 06:02:11 +02:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|