summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2017-02-22 19:50:27 +0100
committerSergei Golubchik <serg@mariadb.org>2017-02-28 16:19:44 +0100
commit370cf70136778b4b89bc3d3d2dfc8a35c7f98478 (patch)
treec221b832e1a751d76835aab9fd978f96c57799db /storage
parent6a12c05347beb85a95318568e5f78221bde73b38 (diff)
downloadmariadb-git-370cf70136778b4b89bc3d3d2dfc8a35c7f98478.tar.gz
MDEV-11757 KEY_BLOCK_SIZE strangeness when UNCOMPRESSing COMPRESSed InnoDB tables
in ALTER TABLE ... DROP KEY, ADD KEY, don't forget to compare old and new keys' block sizes. If they differ - the key definition has changed.
Diffstat (limited to 'storage')
-rw-r--r--storage/myisam/ha_myisam.cc68
-rw-r--r--storage/myisam/ha_myisam.h2
2 files changed, 70 insertions, 0 deletions
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index dac01b8af89..730a63067ac 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -2179,6 +2179,74 @@ uint ha_myisam::checksum() const
}
+enum_alter_inplace_result
+ha_myisam::check_if_supported_inplace_alter(TABLE *new_table,
+ Alter_inplace_info *alter_info)
+{
+ DBUG_ENTER("ha_myisam::check_if_supported_inplace_alter");
+
+ const uint readd_index= Alter_inplace_info::ADD_INDEX |
+ Alter_inplace_info::DROP_INDEX;
+ const uint readd_unique= Alter_inplace_info::ADD_UNIQUE_INDEX |
+ Alter_inplace_info::DROP_UNIQUE_INDEX;
+ const uint readd_pk= Alter_inplace_info::ADD_PK_INDEX |
+ Alter_inplace_info::DROP_PK_INDEX;
+
+ const uint op= alter_info->handler_flags;
+
+ /*
+ ha_myisam::open() updates table->key_info->block_size to be the actual
+ MYI index block size, overwriting user-specified value (if any).
+ So, the server can not reliably detect whether ALTER TABLE changes
+ key_block_size or not, it might think the block size was changed,
+ when it wasn't, and in this case the server will recreate (drop+add)
+ the index unnecessary. Fix it.
+ */
+
+ if (table->s->keys == new_table->s->keys &&
+ ((op & readd_pk) == readd_pk ||
+ (op & readd_unique) == readd_unique ||
+ (op & readd_index) == readd_index))
+ {
+ for (uint i=0; i < table->s->keys; i++)
+ {
+ KEY *old_key= table->key_info + i;
+ KEY *new_key= new_table->key_info + i;
+
+ if (old_key->block_size == new_key->block_size)
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); // must differ somewhere else
+
+ if (new_key->block_size && new_key->block_size != old_key->block_size)
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); // really changed
+
+ /* any difference besides the block_size, and we give up */
+ if (old_key->key_length != new_key->key_length ||
+ old_key->flags != new_key->flags ||
+ old_key->user_defined_key_parts != new_key->user_defined_key_parts ||
+ old_key->algorithm != new_key->algorithm ||
+ strcmp(old_key->name, new_key->name))
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+
+ for (uint j= 0; j < old_key->user_defined_key_parts; j++)
+ {
+ KEY_PART_INFO *old_kp= old_key->key_part + j;
+ KEY_PART_INFO *new_kp= new_key->key_part + j;
+ if (old_kp->offset != new_kp->offset ||
+ old_kp->null_offset != new_kp->null_offset ||
+ old_kp->length != new_kp->length ||
+ old_kp->fieldnr != new_kp->fieldnr ||
+ old_kp->key_part_flag != new_kp->key_part_flag ||
+ old_kp->type != new_kp->type ||
+ old_kp->null_bit != new_kp->null_bit)
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ }
+ alter_info->handler_flags &= ~(readd_pk | readd_unique | readd_index);
+ }
+ DBUG_RETURN(handler::check_if_supported_inplace_alter(new_table, alter_info));
+}
+
+
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes)
{
diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
index 63fb0ea5a2a..b132c955795 100644
--- a/storage/myisam/ha_myisam.h
+++ b/storage/myisam/ha_myisam.h
@@ -138,6 +138,8 @@ class ha_myisam: public handler
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt);
int preload_keys(THD* thd, HA_CHECK_OPT* check_opt);
+ enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *new_table,
+ Alter_inplace_info *alter_info);
bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
#ifdef HAVE_QUERY_CACHE
my_bool register_query_cache_table(THD *thd, char *table_key,