diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result index 3bd7fe6b175..fed03cd8d71 100644 --- a/mysql-test/r/type_varchar.result +++ b/mysql-test/r/type_varchar.result @@ -392,3 +392,26 @@ group by t1.b, t1.a; a b min(t1.b) 22 NULL NULL drop table t1, t2; +create table t1 (f1 varchar(65500)); +create index index1 on t1(f1(10)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` varchar(65500) default NULL, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify f1 varchar(255); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` varchar(255) default NULL, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 modify f1 tinytext; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` tinytext, + KEY `index1` (`f1`(10)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/t/type_varchar.test b/mysql-test/t/type_varchar.test index 2bffca6b889..1a3a93018a4 100644 --- a/mysql-test/t/type_varchar.test +++ b/mysql-test/t/type_varchar.test @@ -118,3 +118,15 @@ insert into t2 values (22), (22); select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a group by t1.b, t1.a; drop table t1, t2; + +# +# Bug #10543: convert varchar with index to text +# +create table t1 (f1 varchar(65500)); +create index index1 on t1(f1(10)); +show create table t1; +alter table t1 modify f1 varchar(255); +show create table t1; +alter table t1 modify f1 tinytext; +show create table t1; +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index 54ed4044de5..18f201243dd 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -982,6 +982,39 @@ Item_result Field::result_merge_type(enum_field_types field_type) Static help functions *****************************************************************************/ + +/* + Check whether a field type can be partially indexed by a key + + This is a static method, rather than a virtual function, because we need + to check the type of a non-Field in mysql_alter_table(). + + SYNOPSIS + type_can_have_key_part() + type field type + + RETURN + TRUE Type can have a prefixed key + FALSE Type can not have a prefixed key +*/ + +bool Field::type_can_have_key_part(enum enum_field_types type) +{ + switch (type) { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + return TRUE; + default: + return FALSE; + } +} + + /* Numeric fields base class constructor */ diff --git a/sql/field.h b/sql/field.h index f68a2327dff..8510c59c9f2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -119,6 +119,7 @@ public: virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } virtual Item_result cast_to_int_type () const { return result_type(); } + static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4ddef3fc653..2768d503751 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3334,12 +3334,21 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, continue; // Field is removed uint key_part_length=key_part->length; if (cfield->field) // Not new field - { // Check if sub key - if (cfield->field->type() != FIELD_TYPE_BLOB && - (cfield->field->pack_length() == key_part_length || - cfield->length <= key_part_length / - key_part->field->charset()->mbmaxlen)) - key_part_length=0; // Use whole field + { + /* + If the field can't have only a part used in a key according to its + new type, or should not be used partially according to its + previous type, or the field length is less than the key part + length, unset the key part length. + + BLOBs may have cfield->length == 0, which is why we test it before + checking whether cfield->length < key_part_length (in chars). + */ + if (!Field::type_can_have_key_part(cfield->field->type()) || + !Field::type_can_have_key_part(cfield->sql_type) || + (cfield->length && (cfield->length < key_part_length / + key_part->field->charset()->mbmaxlen))) + key_part_length= 0; // Use whole field } key_part_length /= key_part->field->charset()->mbmaxlen; key_parts.push_back(new key_part_spec(cfield->field_name,