1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

NFC: refactor Field::is_equal() and related stuff

Make Field::is_equal() const and return bool as it's a naturally fitting
type for it. Also it's agrument was narrowed to Column_definition.

InnoDB can change type of some columns by itself. InnoDB-specific code used to
reside in Field_xxx:is_equal() methods. Now engine-specific stuff was
moved to a virtual methods of handler::can_convert{string,varstring,blob,geom}.
These methods are called by Field::can_be_converted_by_engine() which is a
double dispatch pattern.

Some InnoDB-specific code still resides in compare_keys_but_name(). It should
be moved from here someday to handler::compare_key_parts(...) or similar.

IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET
IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE: both was removed

IS_EQUAL_NO, IS_EQUAL_YES are not needed now and should be removed
along with deprecated handler::check_if_incompatible_data().

HA_EXTENDED_TYPES_CONVERSION: was removed as such logic is not needed now by
server code.

ALTER_COLUMN_EQUAL_PACK_LENGTH: was renamed to a more generic
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE
This commit is contained in:
Eugene Kosov
2019-06-17 16:54:47 +03:00
parent 854c219a7f
commit a82e42fd13
15 changed files with 356 additions and 278 deletions

View File

@@ -6560,27 +6560,28 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
if the user key part length is different.
*/
const Field *old_field= table->field[key_part->fieldnr - 1];
auto old_field_len= old_field->pack_length();
if (old_field->type() == MYSQL_TYPE_VARCHAR)
bool is_equal= key_part->field->is_equal(*new_field);
/* TODO: below is an InnoDB specific code which should be moved to InnoDB */
if (!is_equal)
{
old_field_len= (old_field->pack_length() -
((Field_varstring *) old_field)->length_bytes);
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;
}
uint is_equal= key_part->field->is_equal(new_field);
if (key_part->length == old_field_len &&
key_part->length < new_part->length &&
(is_equal == IS_EQUAL_PACK_LENGTH ||
is_equal == IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET))
if (key_part->length != new_part->length)
{
if (key_part->length != old_field->field_length ||
key_part->length >= new_part->length || is_equal)
{
return Compare_keys::NotEqual;
}
result= Compare_keys::EqualButKeyPartLength;
}
else if (key_part->length != new_part->length)
return Compare_keys::NotEqual;
if (is_equal == IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE)
return Compare_keys::NotEqual;
}
/*
@@ -6602,40 +6603,6 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
return result;
}
/**
Change Field::is_equal() result depending on field being a part of some index.
*/
static uint process_is_equal_result_for_key_parts(uint is_equal,
const Field *old_field,
const Create_field *new_field)
{
if (is_equal == IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET)
return IS_EQUAL_PACK_LENGTH;
if (is_equal == IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE)
{
bool part_of_a_key= !new_field->field->part_of_key.is_clear_all();
if (part_of_a_key)
{
const TABLE_SHARE *s= new_field->field->table->s;
bool part_of_a_primary_key=
s->primary_key != MAX_KEY &&
new_field->field->part_of_key.is_set(s->primary_key);
if (part_of_a_primary_key)
return IS_EQUAL_NO;
return IS_EQUAL_PACK_LENGTH;
}
return IS_EQUAL_PACK_LENGTH;
}
return is_equal;
}
/**
Compare original and new versions of a table and fill Alter_inplace_info
describing differences between those versions.
@@ -6770,61 +6737,50 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
/* Field is not dropped. Evaluate changes bitmap for it. */
/*
Check if type of column has changed to some incompatible type.
Check if type of column has changed.
*/
uint is_equal= field->is_equal(new_field);
switch (process_is_equal_result_for_key_parts(is_equal, field, new_field))
bool is_equal= field->is_equal(*new_field);
if (!is_equal)
{
case IS_EQUAL_NO:
/* New column type is incompatible with old one. */
if (field->stored_in_db())
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
else
ha_alter_info->handler_flags|= ALTER_VIRTUAL_COLUMN_TYPE;
if (table->s->tmp_table == NO_TMP_TABLE)
if (field->can_be_converted_by_engine(*new_field))
{
delete_statistics_for_column(thd, table, field);
KEY *key_info= table->key_info;
for (uint i=0; i < table->s->keys; i++, key_info++)
/*
New column type differs from the old one, but storage engine can
change it by itself.
(for example, VARCHAR(300) is changed to VARCHAR(400)).
*/
ha_alter_info->handler_flags|= ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE;
}
else
{
/* New column type is incompatible with old one. */
ha_alter_info->handler_flags|= field->stored_in_db()
? ALTER_STORED_COLUMN_TYPE
: ALTER_VIRTUAL_COLUMN_TYPE;
if (table->s->tmp_table == NO_TMP_TABLE)
{
if (field->part_of_key.is_set(i))
delete_statistics_for_column(thd, table, field);
KEY *key_info= table->key_info;
for (uint i= 0; i < table->s->keys; i++, key_info++)
{
if (!field->part_of_key.is_set(i))
continue;
uint key_parts= table->actual_n_key_parts(key_info);
for (uint j= 0; j < key_parts; j++)
{
if (key_info->key_part[j].fieldnr-1 == field->field_index)
if (key_info->key_part[j].fieldnr - 1 == field->field_index)
{
delete_statistics_for_index(thd, table, key_info,
j >= key_info->user_defined_key_parts);
delete_statistics_for_index(
thd, table, key_info,
j >= key_info->user_defined_key_parts);
break;
}
}
}
}
}
}
}
break;
case IS_EQUAL_YES:
/*
New column is the same as the old one or the fully compatible with
it (for example, ENUM('a','b') was changed to ENUM('a','b','c')).
Such a change if any can ALWAYS be carried out by simply updating
data-dictionary without even informing storage engine.
No flag is set in this case.
*/
break;
case IS_EQUAL_PACK_LENGTH:
/*
New column type differs from the old one, but has compatible packed
data representation. Depending on storage engine, such a change can
be carried out by simply updating data dictionary without changing
actual data (for example, VARCHAR(300) is changed to VARCHAR(400)).
*/
ha_alter_info->handler_flags|= ALTER_COLUMN_EQUAL_PACK_LENGTH;
break;
default:
DBUG_ASSERT(0);
/* Safety. */
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
}
if (field->vcol_info || new_field->vcol_info)
@@ -6835,7 +6791,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
ALTER_VIRTUAL_COLUMN_TYPE);
if (field->vcol_info && new_field->vcol_info)
{
bool value_changes= is_equal == IS_EQUAL_NO;
bool value_changes= !is_equal;
alter_table_operations alter_expr;
if (field->stored_in_db())
alter_expr= ALTER_STORED_GCOL_EXPR;
@@ -6929,7 +6885,6 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]=
new_field->option_struct;
}
}
else
{
@@ -7294,7 +7249,7 @@ bool mysql_compare_tables(TABLE *table,
DBUG_RETURN(false);
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
uint field_changes= field->is_equal(tmp_new_field);
uint field_changes= field->is_equal(*tmp_new_field);
if (field_changes != IS_EQUAL_YES)
DBUG_RETURN(false);
@@ -8797,7 +8752,7 @@ fk_check_column_changes(THD *thd, Alter_info *alter_info,
return FK_COLUMN_RENAMED;
}
if ((old_field->is_equal(new_field) == IS_EQUAL_NO) ||
if ((old_field->is_equal(*new_field) == IS_EQUAL_NO) ||
((new_field->flags & NOT_NULL_FLAG) &&
!(old_field->flags & NOT_NULL_FLAG)))
{