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

@ -2449,12 +2449,12 @@ void Field_null::sql_type(String &res) const
}
uint Field_null::is_equal(Create_field *new_field)
bool Field_null::is_equal(const Column_definition &new_field) const
{
DBUG_ASSERT(!compression_method());
return new_field->type_handler() == type_handler() &&
new_field->charset == field_charset &&
new_field->length == max_display_length();
return new_field.type_handler() == type_handler() &&
new_field.charset == field_charset &&
new_field.length == max_display_length();
}
@ -3492,15 +3492,15 @@ bool Field_new_decimal::compatible_field_size(uint field_metadata,
}
uint Field_new_decimal::is_equal(Create_field *new_field)
bool Field_new_decimal::is_equal(const Column_definition &new_field) const
{
return ((new_field->type_handler() == type_handler()) &&
((new_field->flags & UNSIGNED_FLAG) ==
return ((new_field.type_handler() == type_handler()) &&
((new_field.flags & UNSIGNED_FLAG) ==
(uint) (flags & UNSIGNED_FLAG)) &&
((new_field->flags & AUTO_INCREMENT_FLAG) <=
((new_field.flags & AUTO_INCREMENT_FLAG) <=
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
(new_field->length == max_display_length()) &&
(new_field->decimals == dec));
(new_field.length == max_display_length()) &&
(new_field.decimals == dec));
}
@ -5585,10 +5585,10 @@ bool Field_timestampf::val_native(Native *to)
/*************************************************************/
uint Field_temporal::is_equal(Create_field *new_field)
bool Field_temporal::is_equal(const Column_definition &new_field) const
{
return new_field->type_handler() == type_handler() &&
new_field->length == max_display_length();
return new_field.type_handler() == type_handler() &&
new_field.length == max_display_length();
}
@ -7073,40 +7073,13 @@ int Field_str::store(double nr)
return store(buff, (uint)length, &my_charset_numeric);
}
uint Field_longstr::
is_equal_for_different_charsets(const Column_definition &to) const
{
Charset field_cs(field_charset);
if (!field_cs.encoding_allows_reinterpret_as(to.charset))
return IS_EQUAL_NO;
if (!field_cs.eq_collation_specific_names(to.charset))
return IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE;
return IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET;
}
uint Field_string::is_equal(Create_field *new_field)
bool Field_string::is_equal(const Column_definition &new_field) const
{
DBUG_ASSERT(!compression_method());
if (new_field->type_handler() != type_handler())
return IS_EQUAL_NO;
if (new_field->char_length < char_length())
return IS_EQUAL_NO;
if (new_field->charset != field_charset)
{
if (new_field->length != max_display_length() &&
table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION)
return IS_EQUAL_NO;
return is_equal_for_different_charsets(*new_field);
}
if (new_field->length != max_display_length())
return IS_EQUAL_NO;
return IS_EQUAL_YES;
return new_field.type_handler() == type_handler() &&
new_field.char_length == char_length() &&
new_field.charset == field_charset &&
new_field.length == max_display_length();
}
@ -7940,48 +7913,13 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table,
return res;
}
/*
This check is InnoDB specific. ROW_FORMAT=REDUNDANT always allows such
enlargement. But other row formats can do this only for particular current
and new lengths. This is because InnoDB stores VARCHAR length in one or two
bytes.
*/
static bool supports_such_enlargement(const Field *field,
const Create_field *new_field)
bool Field_varstring::is_equal(const Column_definition &new_field) const
{
return field->field_length <= 127 || new_field->length <= 255 ||
field->field_length > 255 ||
(field->table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION);
}
uint Field_varstring::is_equal(Create_field *new_field)
{
if (new_field->length < field_length)
return IS_EQUAL_NO;
if (new_field->char_length < char_length())
return IS_EQUAL_NO;
if (!new_field->compression_method() != !compression_method())
return IS_EQUAL_NO;
if (new_field->type_handler() != type_handler())
return IS_EQUAL_NO;
if (new_field->charset != field_charset)
{
if (!supports_such_enlargement(this, new_field))
return IS_EQUAL_NO;
return is_equal_for_different_charsets(*new_field);
}
if (new_field->length != field_length)
{
if (!supports_such_enlargement(this, new_field))
return IS_EQUAL_NO;
return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer length
}
return IS_EQUAL_YES;
return new_field.type_handler() == type_handler() &&
new_field.length == field_length &&
new_field.char_length == char_length() &&
!new_field.compression_method() == !compression_method() &&
new_field.charset == field_charset;
}
@ -8745,21 +8683,12 @@ uint Field_blob::max_packed_col_length(uint max_length)
again an already compressed field just because compression method changes.
*/
uint Field_blob::is_equal(Create_field *new_field)
bool Field_blob::is_equal(const Column_definition &new_field) const
{
if (new_field->type_handler() != type_handler())
return IS_EQUAL_NO;
if (!new_field->compression_method() != !compression_method())
return IS_EQUAL_NO;
if (new_field->pack_length != pack_length())
return IS_EQUAL_NO;
if (field_charset != new_field->charset)
return is_equal_for_different_charsets(*new_field);
return IS_EQUAL_YES;
return new_field.type_handler() == type_handler() &&
!new_field.compression_method() == !compression_method() &&
new_field.pack_length == pack_length() &&
new_field.charset == field_charset;
}
@ -9068,16 +8997,16 @@ Field::geometry_type Field_geom::geometry_type_merge(geometry_type a,
}
uint Field_geom::is_equal(Create_field *new_field)
bool Field_geom::is_equal(const Column_definition &new_field) const
{
return new_field->type_handler() == type_handler() &&
return new_field.type_handler() == type_handler() &&
/*
- Allow ALTER..INPLACE to supertype (GEOMETRY),
e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
- Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
*/
(new_field->geom_type == geom_type ||
new_field->geom_type == GEOM_GEOMETRY);
(new_field.geom_type == geom_type ||
new_field.geom_type == GEOM_GEOMETRY);
}
@ -9507,22 +9436,22 @@ bool Field_enum::eq_def(const Field *field) const
alteration purposes. Fields are equal if they retain the same
pack length and if new members are added to the end of the list.
@return IS_EQUAL_YES if fields are compatible.
IS_EQUAL_NO otherwise.
@return true if fields are compatible.
false otherwise.
*/
uint Field_enum::is_equal(Create_field *new_field)
bool Field_enum::is_equal(const Column_definition &new_field) const
{
TYPELIB *values= new_field->interval;
TYPELIB *values= new_field.interval;
/*
The fields are compatible if they have the same flags,
type, charset and have the same underlying length.
*/
if (new_field->type_handler() != type_handler() ||
new_field->charset != field_charset ||
new_field->pack_length != pack_length())
return IS_EQUAL_NO;
if (new_field.type_handler() != type_handler() ||
new_field.charset != field_charset ||
new_field.pack_length != pack_length())
return false;
/*
Changing the definition of an ENUM or SET column by adding a new
@ -9530,13 +9459,13 @@ uint Field_enum::is_equal(Create_field *new_field)
values only alters table metadata and not table data.
*/
if (typelib->count > values->count)
return IS_EQUAL_NO;
return false;
/* Check whether there are modification before the end. */
if (! compare_type_names(field_charset, typelib, new_field->interval))
return IS_EQUAL_NO;
if (! compare_type_names(field_charset, typelib, new_field.interval))
return false;
return IS_EQUAL_YES;
return true;
}
@ -9582,17 +9511,17 @@ bool Field_num::eq_def(const Field *field) const
and retain the same pack length.
*/
uint Field_num::is_equal(Create_field *new_field)
bool Field_num::is_equal(const Column_definition &new_field) const
{
if (((new_field->flags & UNSIGNED_FLAG) != (flags & UNSIGNED_FLAG)) ||
((new_field->flags & AUTO_INCREMENT_FLAG) > (flags & AUTO_INCREMENT_FLAG)))
return IS_EQUAL_NO;
if (((new_field.flags & UNSIGNED_FLAG) != (flags & UNSIGNED_FLAG)) ||
((new_field.flags & AUTO_INCREMENT_FLAG) > (flags & AUTO_INCREMENT_FLAG)))
return false;
const Type_handler *th= type_handler(), *new_th = new_field->type_handler();
const Type_handler *th= type_handler(), *new_th = new_field.type_handler();
if (th == new_th && new_field->pack_length == pack_length())
return IS_EQUAL_YES;
/* FIXME: Test and consider returning IS_EQUAL_YES for the following:
if (th == new_th && new_field.pack_length == pack_length())
return true;
/* FIXME: Test and consider returning true for the following:
TINYINT UNSIGNED to BIT(8)
SMALLINT UNSIGNED to BIT(16)
MEDIUMINT UNSIGNED to BIT(24)
@ -9607,10 +9536,10 @@ uint Field_num::is_equal(Create_field *new_field)
Note: InnoDB stores integers in big-endian format, and BIT appears
to use big-endian format. For storage engines that use little-endian
format for integers, we can only return IS_EQUAL_YES for the TINYINT
format for integers, we can only return true for the TINYINT
conversion. */
return IS_EQUAL_NO;
return false;
}
@ -9757,10 +9686,10 @@ Field *Field_bit::new_key_field(MEM_ROOT *root, TABLE *new_table,
}
uint Field_bit::is_equal(Create_field *new_field)
bool Field_bit::is_equal(const Column_definition &new_field) const
{
return new_field->type_handler() == type_handler() &&
new_field->length == max_display_length();
return new_field.type_handler() == type_handler() &&
new_field.length == max_display_length();
}

View File

@ -1503,13 +1503,16 @@ public:
/* maximum possible display length */
virtual uint32 max_display_length() const= 0;
/**
Whether a field being created is compatible with a existing one.
Used by the ALTER TABLE code to evaluate whether the new definition
of a table is compatible with the old definition so that it can
determine if data needs to be copied over (table data change).
Whether a field being created has the samle type.
Used by the ALTER TABLE
*/
virtual uint is_equal(Create_field *new_field)= 0;
virtual bool is_equal(const Column_definition &new_field) const= 0;
// Used as double dispatch pattern: calls virtual method of handler
virtual bool
can_be_converted_by_engine(const Column_definition &new_type) const
{
return false;
}
/* convert decimal to longlong with overflow check */
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err);
@ -1809,7 +1812,7 @@ public:
!((flags & UNSIGNED_FLAG) && !(from->flags & UNSIGNED_FLAG)) &&
decimals() == from->decimals();
}
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
uint row_pack_length() const { return pack_length(); }
uint32 pack_length_from_metadata(uint field_metadata) {
uint32 length= pack_length();
@ -1874,7 +1877,7 @@ public:
bool val_bool() { return val_real() != 0e0; }
virtual bool str_needs_quotes() { return TRUE; }
bool eq_cmp_as_binary() { return MY_TEST(flags & BINARY_FLAG); }
virtual uint length_size() { return 0; }
virtual uint length_size() const { return 0; }
double pos_in_interval(Field *min, Field *max)
{
return pos_in_interval_val_str(min, max, length_size());
@ -1928,8 +1931,6 @@ protected:
CHARSET_INFO *cs, size_t nchars);
String *uncompress(String *val_buffer, String *val_ptr,
const uchar *from, uint from_length);
uint is_equal_for_different_charsets(const Column_definition &to) const;
public:
Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@ -2142,7 +2143,7 @@ public:
uint row_pack_length() const { return pack_length(); }
bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
uint16 mflags, int *order_var);
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
};
@ -2646,7 +2647,7 @@ public:
my_decimal *val_decimal(my_decimal *) { return 0; }
String *val_str(String *value,String *value2)
{ value2->length(0); return value2;}
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
int cmp(const uchar *a, const uchar *b) { return 0;}
void sort_string(uchar *buff, uint length) {}
uint32 pack_length() const { return 0; }
@ -2729,7 +2730,7 @@ public:
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
bool binary() const { return true; }
bool val_bool() { return val_real() != 0e0; }
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
bool eq_def(const Field *field) const
{
return (Field::eq_def(field) && decimals() == field->decimals());
@ -3570,7 +3571,11 @@ public:
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
void sql_type(String &str) const;
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
{
return table->file->can_convert_string(this, new_type);
}
virtual uchar *pack(uchar *to, const uchar *from,
uint max_length);
virtual const uchar *unpack(uchar* to, const uchar *from,
@ -3698,9 +3703,13 @@ public:
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
uchar *new_null_ptr, uint new_null_bit);
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
{
return table->file->can_convert_varstring(this, new_type);
}
void hash(ulong *nr, ulong *nr2);
uint length_size() { return length_bytes; }
uint length_size() const { return length_bytes; }
void print_key_value(String *out, uint32 length);
private:
int save_field_metadata(uchar *first_byte);
@ -4039,7 +4048,11 @@ public:
uint32 max_display_length() const;
uint32 char_length() const;
uint32 character_octet_length() const;
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
{
return table->file->can_convert_blob(this, new_type);
}
void print_key_value(String *out, uint32 length);
friend void TABLE::remember_blob_values(String *blob_storage);
@ -4154,7 +4167,12 @@ public:
geom_type == static_cast<const Field_geom*>(from)->geom_type) &&
!table->copy_blobs;
}
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
{
return table->file->can_convert_geom(this, new_type);
}
int store(const char *to, size_t length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@ -4298,7 +4316,7 @@ public:
bool is_eq_func) const;
private:
int save_field_metadata(uchar *first_byte);
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
};
@ -4477,7 +4495,7 @@ public:
bit_ptr == ((Field_bit *)field)->bit_ptr &&
bit_ofs == ((Field_bit *)field)->bit_ofs);
}
uint is_equal(Create_field *new_field);
bool is_equal(const Column_definition &new_field) const;
void move_field_offset(my_ptrdiff_t ptr_diff)
{
Field::move_field_offset(ptr_diff);

View File

@ -4593,7 +4593,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
alter_table_operations inplace_offline_operations=
ALTER_COLUMN_EQUAL_PACK_LENGTH |
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE |
ALTER_COLUMN_NAME |
ALTER_RENAME_COLUMN |
ALTER_CHANGE_COLUMN_DEFAULT |
@ -4629,7 +4629,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
uint table_changes= (ha_alter_info->handler_flags &
ALTER_COLUMN_EQUAL_PACK_LENGTH) ?
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) ?
IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES;
if (table->file->check_if_incompatible_data(create_info, table_changes)
== COMPATIBLE_DATA_YES)

View File

@ -49,6 +49,11 @@ class Alter_info;
class Virtual_column_info;
class sequence_definition;
class Rowid_filter;
class Field_string;
class Field_varstring;
class Field_blob;
class Field_geom;
class Column_definition;
// the following is for checking tables
@ -321,10 +326,6 @@ enum enum_alter_inplace_result {
/* Safe for online backup */
#define HA_CAN_ONLINE_BACKUPS (1ULL << 56)
/** whether every data field explicitly stores length
(holds for InnoDB ROW_FORMAT=REDUNDANT) */
#define HA_EXTENDED_TYPES_CONVERSION (1ULL << 57)
/* Support native hash index */
#define HA_CAN_HASH_KEYS (1ULL << 58)
#define HA_LAST_TABLE_FLAG HA_CAN_HASH_KEYS
@ -706,13 +707,9 @@ typedef ulonglong alter_table_operations;
#define ALTER_VIRTUAL_COLUMN_TYPE (1ULL << 47)
#define ALTER_STORED_COLUMN_TYPE (1ULL << 48)
/**
Change column datatype in such way that new type has compatible
packed representation with old type, so it is theoretically
possible to perform change by only updating data dictionary
without changing table rows.
*/
#define ALTER_COLUMN_EQUAL_PACK_LENGTH (1ULL << 49)
// Engine can handle type change by itself in ALGORITHM=INPLACE
#define ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE (1ULL << 49)
// Reorder column
#define ALTER_STORED_COLUMN_ORDER (1ULL << 50)
@ -4815,6 +4812,32 @@ public:
virtual bool is_clustering_key(uint index) { return false; }
/**
Some engines can perform column type conversion with ALGORITHM=INPLACE.
These functions check for such possibility.
Implementation could be based on Field_xxx::is_equal()
*/
virtual bool can_convert_string(const Field_string *field,
const Column_definition &new_type) const
{
return false;
}
virtual bool can_convert_varstring(const Field_varstring *field,
const Column_definition &new_type) const
{
return false;
}
virtual bool can_convert_blob(const Field_blob *field,
const Column_definition &new_type) const
{
return false;
}
virtual bool can_convert_geom(const Field_geom *field,
const Column_definition &new_type) const
{
return false;
}
protected:
Handler_share *get_ha_share_ptr();
void set_ha_share_ptr(Handler_share *arg_ha_share);

View File

@ -354,14 +354,6 @@
data dictionary without changing table rows
*/
#define IS_EQUAL_PACK_LENGTH 2
/**
charsets are the same or compatible, collates are the same, the rest is equal
*/
#define IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET 3
/**
charsets are the same or compatible, collates are different, the rest is equal
*/
#define IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET_BUT_COLLATE 4
enum enum_parsing_place
{

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)))
{

View File

@ -8367,6 +8367,5 @@ Charset::eq_collation_specific_names(CHARSET_INFO *cs) const
{
LEX_CSTRING name0= collation_specific_name();
LEX_CSTRING name1= Charset(cs).collation_specific_name();
/* Empty collations are not equal */
return name0.length && !cmp(&name0, &name1);
}

View File

@ -7018,7 +7018,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table,
ALTER_DROP_PK_INDEX;
alter_table_operations inplace_offline_operations=
ALTER_COLUMN_EQUAL_PACK_LENGTH |
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE |
ALTER_COLUMN_NAME |
ALTER_COLUMN_DEFAULT |
ALTER_CHANGE_CREATE_OPTION |
@ -7117,7 +7117,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table,
#if 0
uint table_changes= (ha_alter_info->handler_flags &
ALTER_COLUMN_EQUAL_PACK_LENGTH) ?
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) ?
IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES;
if (table->file->check_if_incompatible_data(create_info, table_changes)

View File

@ -74,6 +74,8 @@ Warnings:
Warning 1105 Truncated author content
# increase author size
ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
Warnings:
Warning 1105 This is an outward table, table data were not modified.
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00

View File

@ -72,6 +72,8 @@ Warnings:
Warning 1105 Truncated author content
# increase author size
ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
Warnings:
Warning 1105 This is an outward table, table data were not modified.
SELECT * FROM bookstore;
category title lang author year price
COOKING Everyday Italian en Giada De Laurentiis 2005 30.00

View File

@ -54,6 +54,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include <my_bitmap.h>
#include <mysql/service_thd_alloc.h>
#include <mysql/service_thd_wait.h>
#include "field.h"
// MYSQL_PLUGIN_IMPORT extern my_bool lower_case_file_system;
// MYSQL_PLUGIN_IMPORT extern char mysql_unpacked_real_data_home[];
@ -6141,11 +6142,6 @@ no_such_table:
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
if (!ib_table->not_redundant()) {
m_int_table_flags |= HA_EXTENDED_TYPES_CONVERSION;
cached_table_flags |= HA_EXTENDED_TYPES_CONVERSION;
}
size_t n_fields = omits_virtual_cols(*table_share)
? table_share->stored_fields : table_share->fields;
size_t n_cols = dict_table_get_n_user_cols(ib_table)
@ -20875,6 +20871,146 @@ bool ha_innobase::rowid_filter_push(Rowid_filter* pk_filter)
DBUG_RETURN(false);
}
static bool
is_part_of_a_primary_key(const Field* field)
{
const TABLE_SHARE* s = field->table->s;
return s->primary_key != MAX_KEY
&& field->part_of_key.is_set(s->primary_key);
}
bool
ha_innobase::can_convert_string(const Field_string* field,
const Column_definition& new_type) const
{
DBUG_ASSERT(!field->compression_method());
if (new_type.type_handler() != field->type_handler()) {
return false;
}
if (new_type.char_length < field->char_length()) {
return false;
}
if (new_type.charset != field->charset()) {
if (new_type.length != field->max_display_length()
&& !m_prebuilt->table->not_redundant()) {
return IS_EQUAL_NO;
}
Charset field_cs(field->charset());
if (!field_cs.encoding_allows_reinterpret_as(
new_type.charset)) {
return false;
}
if (!field_cs.eq_collation_specific_names(new_type.charset)) {
return !is_part_of_a_primary_key(field);
}
return true;
}
if (new_type.length != field->max_display_length()) {
return false;
}
return true;
}
static bool
supports_enlarging(const dict_table_t* table, const Field_varstring* field,
const Column_definition& new_type)
{
return field->field_length <= 127 || new_type.length <= 255
|| field->field_length > 255 || !table->not_redundant();
}
bool
ha_innobase::can_convert_varstring(const Field_varstring* field,
const Column_definition& new_type) const
{
if (new_type.length < field->field_length) {
return false;
}
if (new_type.char_length < field->char_length()) {
return false;
}
if (!new_type.compression_method() != !field->compression_method()) {
return false;
}
if (new_type.type_handler() != field->type_handler()) {
return false;
}
if (new_type.charset != field->charset()) {
if (!supports_enlarging(m_prebuilt->table, field, new_type)) {
return false;
}
Charset field_cs(field->charset());
if (!field_cs.encoding_allows_reinterpret_as(
new_type.charset)) {
return false;
}
if (!field_cs.eq_collation_specific_names(new_type.charset)) {
return !is_part_of_a_primary_key(field);
}
return true;
}
if (new_type.length != field->field_length) {
if (!supports_enlarging(m_prebuilt->table, field, new_type)) {
return false;
}
return true;
}
return true;
}
bool
ha_innobase::can_convert_blob(const Field_blob* field,
const Column_definition& new_type) const
{
if (new_type.type_handler() != field->type_handler()) {
return false;
}
if (!new_type.compression_method() != !field->compression_method()) {
return false;
}
if (new_type.pack_length != field->pack_length()) {
return false;
}
if (new_type.charset != field->charset()) {
Charset field_cs(field->charset());
if (!field_cs.encoding_allows_reinterpret_as(
new_type.charset)) {
return false;
}
if (!field_cs.eq_collation_specific_names(new_type.charset)) {
bool is_part_of_a_key
= !field->part_of_key.is_clear_all();
return !is_part_of_a_key;
}
return true;
}
return true;
}
/******************************************************************//**
Use this when the args are passed to the format string from
errmsg-utf8.txt directly as is.

View File

@ -437,6 +437,13 @@ public:
@retval false if pushed (always) */
bool rowid_filter_push(Rowid_filter *rowid_filter);
bool can_convert_string(const Field_string* field,
const Column_definition& new_field) const;
bool can_convert_varstring(const Field_varstring* field,
const Column_definition& new_field) const;
bool can_convert_blob(const Field_blob* field,
const Column_definition& new_field) const;
protected:
/**
MySQL calls this method at the end of each statement. This method

View File

@ -131,7 +131,7 @@ static const alter_table_operations INNOBASE_ALTER_INSTANT
| ALTER_COLUMN_NAME
| ALTER_ADD_VIRTUAL_COLUMN
| INNOBASE_FOREIGN_OPERATIONS
| ALTER_COLUMN_EQUAL_PACK_LENGTH
| ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE
| ALTER_COLUMN_UNVERSIONED
| ALTER_RENAME_INDEX
| ALTER_DROP_VIRTUAL_COLUMN;
@ -8332,7 +8332,7 @@ ok_exit:
rebuild_templ
= ctx->need_rebuild()
|| ((ha_alter_info->handler_flags
& ALTER_COLUMN_EQUAL_PACK_LENGTH)
& ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE)
&& alter_templ_needs_rebuild(
altered_table, ha_alter_info, ctx->new_table));
@ -9194,7 +9194,7 @@ innobase_rename_or_enlarge_columns_try(
DBUG_ENTER("innobase_rename_or_enlarge_columns_try");
if (!(ha_alter_info->handler_flags
& (ALTER_COLUMN_EQUAL_PACK_LENGTH
& (ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE
| ALTER_COLUMN_NAME))) {
DBUG_RETURN(false);
}
@ -9242,7 +9242,7 @@ innobase_rename_or_enlarge_columns_cache(
dict_table_t* user_table)
{
if (!(ha_alter_info->handler_flags
& (ALTER_COLUMN_EQUAL_PACK_LENGTH
& (ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE
| ALTER_COLUMN_NAME))) {
return;
}

View File

@ -916,6 +916,9 @@ public:
Item* idx_cond_push(uint keyno, class Item* idx_cond);
void cancel_pushed_idx_cond();
bool can_convert_varstring(const Field_varstring* field,
const Column_definition&new_type) const;
#if defined(TOKU_INCLUDE_ALTER_56) && TOKU_INCLUDE_ALTER_56
public:
enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ha_alter_info);

View File

@ -465,10 +465,10 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter(
result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
}
} else if ((ctx->handler_flags &
ALTER_COLUMN_EQUAL_PACK_LENGTH) &&
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) &&
only_flags(
ctx->handler_flags,
ALTER_COLUMN_EQUAL_PACK_LENGTH |
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE |
ALTER_COLUMN_DEFAULT) &&
table->s->fields == altered_table->s->fields &&
find_changed_fields(
@ -1180,6 +1180,18 @@ static bool change_varchar_length_is_supported(Field* old_field,
return true;
}
bool ha_tokudb::can_convert_varstring(const Field_varstring* field,
const Column_definition& new_type) const {
if (new_type.length < field->field_length ||
new_type.char_length < field->char_length() ||
!new_type.compression_method() != !field->compression_method() ||
new_type.type_handler() != field->type_handler()) {
return false;
}
return true;
}
// Return true if all changed field lengths can be changed inplace, otherwise
// return false
static bool change_length_is_supported(TABLE* table,