cleanup: key parts comparison

Engine specific code moved to engine.
This commit is contained in:
Eugene Kosov 2019-10-14 16:20:16 +03:00
parent 5a42a114fd
commit 7ccc1710a0
5 changed files with 121 additions and 64 deletions

View file

@ -6953,6 +6953,20 @@ void handler::set_lock_type(enum thr_lock_type lock)
table->reginfo.lock_type= lock; table->reginfo.lock_type= lock;
} }
Compare_keys handler::compare_key_parts(const Field &old_field,
const Column_definition &new_field,
const KEY_PART_INFO &old_part,
const KEY_PART_INFO &new_part) const
{
if (!old_field.is_equal(new_field))
return Compare_keys::NotEqual;
if (old_part.length != new_part.length)
return Compare_keys::NotEqual;
return Compare_keys::Equal;
}
#ifdef WITH_WSREP #ifdef WITH_WSREP
/** /**
@details @details

View file

@ -2936,6 +2936,13 @@ public:
virtual ~Handler_share() {} virtual ~Handler_share() {}
}; };
enum class Compare_keys : uint32_t
{
Equal,
EqualButKeyPartLength,
EqualButComment,
NotEqual
};
/** /**
The handler class is the interface for dynamically loadable The handler class is the interface for dynamically loadable
@ -4877,6 +4884,13 @@ public:
return false; return false;
} }
/* Used for ALTER TABLE.
Some engines can handle some differences in indexes by themself. */
virtual Compare_keys compare_key_parts(const Field &old_field,
const Column_definition &new_field,
const KEY_PART_INFO &old_part,
const KEY_PART_INFO &new_part) const;
protected: protected:
Handler_share *get_ha_share_ptr(); Handler_share *get_ha_share_ptr();
void set_ha_share_ptr(Handler_share *arg_ha_share); void set_ha_share_ptr(Handler_share *arg_ha_share);

View file

@ -6579,38 +6579,68 @@ static int compare_uint(const uint *s, const uint *t)
return (*s < *t) ? -1 : ((*s > *t) ? 1 : 0); return (*s < *t) ? -1 : ((*s > *t) ? 1 : 0);
} }
enum class Compare_keys : uint32_t static Compare_keys merge(Compare_keys current, Compare_keys add) {
{ if (current == Compare_keys::Equal)
Equal, return add;
EqualButKeyPartLength,
EqualButComment, if (add == Compare_keys::Equal)
NotEqual return current;
};
if (current == add)
return current;
if (current == Compare_keys::EqualButComment) {
return Compare_keys::NotEqual;
}
if (current == Compare_keys::EqualButKeyPartLength) {
if (add == Compare_keys::EqualButComment)
return Compare_keys::NotEqual;
DBUG_ASSERT(add == Compare_keys::NotEqual);
return Compare_keys::NotEqual;
}
DBUG_ASSERT(current == Compare_keys::NotEqual);
return current;
}
Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key, Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
Alter_info *alter_info, const TABLE *table, Alter_info *alter_info, const TABLE *table,
const KEY *const new_pk, const KEY *const new_pk,
const KEY *const old_pk) const KEY *const old_pk)
{ {
Compare_keys result= Compare_keys::Equal; if (table_key->algorithm != new_key->algorithm)
return Compare_keys::NotEqual;
if ((table_key->algorithm != new_key->algorithm) || if ((table_key->flags & HA_KEYFLAG_MASK) !=
((table_key->flags & HA_KEYFLAG_MASK) != (new_key->flags & HA_KEYFLAG_MASK))
(new_key->flags & HA_KEYFLAG_MASK)) || return Compare_keys::NotEqual;
(table_key->user_defined_key_parts != new_key->user_defined_key_parts))
if (table_key->user_defined_key_parts != new_key->user_defined_key_parts)
return Compare_keys::NotEqual; return Compare_keys::NotEqual;
if (table_key->block_size != new_key->block_size) if (table_key->block_size != new_key->block_size)
return Compare_keys::NotEqual; return Compare_keys::NotEqual;
/*
Rebuild the index if following condition get satisfied:
(i) Old table doesn't have primary key, new table has it and vice-versa
(ii) Primary key changed to another existing index
*/
if ((new_key == new_pk) != (table_key == old_pk))
return Compare_keys::NotEqual;
if (engine_options_differ(table_key->option_struct, new_key->option_struct, if (engine_options_differ(table_key->option_struct, new_key->option_struct,
table->file->ht->index_options)) table->file->ht->index_options))
return Compare_keys::NotEqual; return Compare_keys::NotEqual;
const KEY_PART_INFO *end= Compare_keys result= Compare_keys::Equal;
table_key->key_part + table_key->user_defined_key_parts;
for (const KEY_PART_INFO *key_part= table_key->key_part, for (const KEY_PART_INFO *
*new_part= new_key->key_part; key_part= table_key->key_part,
*new_part= new_key->key_part,
*end= table_key->key_part + table_key->user_defined_key_parts;
key_part < end; key_part++, new_part++) key_part < end; key_part++, new_part++)
{ {
/* /*
@ -6618,61 +6648,23 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
object with adjusted length. So below we have to check field object with adjusted length. So below we have to check field
indexes instead of simply comparing pointers to Field objects. indexes instead of simply comparing pointers to Field objects.
*/ */
Create_field *new_field= alter_info->create_list.elem(new_part->fieldnr); const Create_field &new_field=
if (!new_field->field || *alter_info->create_list.elem(new_part->fieldnr);
new_field->field->field_index != key_part->fieldnr - 1)
if (!new_field.field ||
new_field.field->field_index != key_part->fieldnr - 1)
{
return Compare_keys::NotEqual; return Compare_keys::NotEqual;
/*
If there is a change in index length due to column expansion
like varchar(X) changed to varchar(X + N) and has a compatible
packed data representation, we mark it for fast/INPLACE change
in index definition. InnoDB supports INPLACE for this cases
Key definition has changed if we are using a different field or
if the user key part length is different.
*/
const Field *old_field= table->field[key_part->fieldnr - 1];
bool is_equal= old_field->is_equal(*new_field);
/* TODO: below is an InnoDB specific code which should be moved to InnoDB */
if (!is_equal)
{
if (!key_part->field->can_be_converted_by_engine(*new_field))
return Compare_keys::NotEqual;
if (!Charset(old_field->charset())
.eq_collation_specific_names(new_field->charset))
return Compare_keys::NotEqual;
} }
if (key_part->length != new_part->length) auto compare= table->file->compare_key_parts(
{ *table->field[key_part->fieldnr - 1], new_field, *key_part, *new_part);
if (key_part->length != old_field->field_length || result= merge(result, compare);
key_part->length >= new_part->length || is_equal)
{
return Compare_keys::NotEqual;
}
result= Compare_keys::EqualButKeyPartLength;
}
} }
/*
Rebuild the index if following condition get satisfied:
(i) Old table doesn't have primary key, new table has it and vice-versa
(ii) Primary key changed to another existing index
*/
if ((new_key == new_pk) != (table_key == old_pk))
return Compare_keys::NotEqual;
/* Check that key comment is not changed. */ /* Check that key comment is not changed. */
if (cmp(table_key->comment, new_key->comment) != 0) if (cmp(table_key->comment, new_key->comment) != 0)
{ result= merge(result, Compare_keys::EqualButComment);
if (result != Compare_keys::Equal)
return Compare_keys::NotEqual;
result= Compare_keys::EqualButComment;
}
return result; return result;
} }

View file

@ -21138,6 +21138,38 @@ ha_innobase::can_convert_blob(const Field_blob* field,
return true; return true;
} }
Compare_keys ha_innobase::compare_key_parts(
const Field &old_field, const Column_definition &new_field,
const KEY_PART_INFO &old_part, const KEY_PART_INFO &new_part) const
{
const bool is_equal= old_field.is_equal(new_field);
if (!is_equal)
{
if (!old_field.can_be_converted_by_engine(new_field))
return Compare_keys::NotEqual;
if (!Charset(old_field.charset())
.eq_collation_specific_names(new_field.charset))
{
return Compare_keys::NotEqual;
}
}
if (old_part.length != new_part.length)
{
if (old_part.length != old_field.field_length ||
old_part.length >= new_part.length || is_equal)
{
return Compare_keys::NotEqual;
}
return Compare_keys::EqualButKeyPartLength;
}
return Compare_keys::Equal;
}
/******************************************************************//** /******************************************************************//**
Use this when the args are passed to the format string from Use this when the args are passed to the format string from
errmsg-utf8.txt directly as is. errmsg-utf8.txt directly as is.

View file

@ -445,6 +445,11 @@ public:
/** @return whether innodb_strict_mode is active */ /** @return whether innodb_strict_mode is active */
bool is_innodb_strict_mode() bool is_innodb_strict_mode()
{ return is_innodb_strict_mode(m_user_thd); } { return is_innodb_strict_mode(m_user_thd); }
Compare_keys
compare_key_parts(const Field& old_field,
const Column_definition& new_field,
const KEY_PART_INFO& old_part,
const KEY_PART_INFO& new_part) const override;
protected: protected:
dberr_t innobase_get_autoinc(ulonglong* value); dberr_t innobase_get_autoinc(ulonglong* value);