1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

MDEV-17301 Change of COLLATE unnecessarily requires ALGORITHM=COPY

Patch is about two cases:
1) On some collate changes it's possible to rebuild only secondary indexes
2) For non-indexed columns collate can be changed INSTANTly

Implemented mostly in Field_{string,varstring,blob}::is_equal().
Make this method return how exactly collationa differs.
This information is later used by fill_alter_inplace_info() to pass
correct info to engine.
This commit is contained in:
Eugene Kosov
2019-06-14 12:18:49 +03:00
parent 72d3676fe5
commit 854c219a7f
10 changed files with 379 additions and 82 deletions

View File

@ -1,10 +1,51 @@
--- instant_alter_charset.result 2019-04-23 17:42:23.324326518 +0400
+++ instant_alter_charset,redundant.result 2019-04-23 17:42:46.047531591 +0400
--- instant_alter_charset.result 2019-06-17 14:36:02.311515062 +0300
+++ instant_alter_charset,redundant.result 2019-06-17 14:50:11.888705725 +0300
@@ -279,7 +279,6 @@
alter table boundary_255
modify a varchar(70) charset utf8mb4,
algorithm=instant;
-ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
drop table boundary_255;
create table fully_compatible (
id int auto_increment unique key,
create table t (
a char(10) collate utf8mb3_general_ci,
@@ -297,32 +296,21 @@
repeat('a', 10), repeat('a', 10)
);
alter table t modify a char(10) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify b char(70) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify c char(100) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify aa char(10) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify bb char(70) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify cc char(100) collate utf8mb4_general_ci, algorithm=instant;
-check table t;
-Table Op Msg_type Msg_text
-test.t check status OK
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify d char(10) collate utf8mb4_spanish_ci, algorithm=instant;
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify dd char(10) collate utf8mb4_spanish_ci, algorithm=instant;
-ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
+ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
select * from t;
a b c aa bb cc d dd
aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaaaaaa

View File

@ -281,6 +281,52 @@ modify a varchar(70) charset utf8mb4,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
drop table boundary_255;
create table t (
a char(10) collate utf8mb3_general_ci,
b char(70) collate utf8mb3_general_ci,
c char(100) collate utf8mb3_general_ci,
aa char(10) collate utf8mb3_general_ci unique,
bb char(70) collate utf8mb3_general_ci unique,
cc char(100) collate utf8mb3_general_ci unique,
d char(10) collate utf8mb3_general_ci,
dd char(10) collate utf8mb3_general_ci unique
) engine=innodb;
insert into t values
(repeat('a', 10), repeat('a', 70), repeat('a', 100),
repeat('a', 10), repeat('a', 70), repeat('a', 100),
repeat('a', 10), repeat('a', 10)
);
alter table t modify a char(10) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify b char(70) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify c char(100) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify aa char(10) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify bb char(70) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify cc char(100) collate utf8mb4_general_ci, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify d char(10) collate utf8mb4_spanish_ci, algorithm=instant;
alter table t modify dd char(10) collate utf8mb4_spanish_ci, algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
select * from t;
a b c aa bb cc d dd
aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaa aaaaaaaaaa
drop table t;
create table fully_compatible (
id int auto_increment unique key,
from_charset char(255),
@ -784,7 +830,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
@ -801,7 +847,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
@ -818,7 +864,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
@ -835,7 +881,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_vietnamese_ci,
algorithm=instant;
@ -852,7 +898,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset ascii collate ascii_bin,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset ascii collate ascii_bin,
algorithm=instant;
@ -869,7 +915,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb3 collate utf8mb3_lithuanian_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb3 collate utf8mb3_lithuanian_ci,
algorithm=instant;
@ -886,7 +932,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_persian_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_persian_ci,
algorithm=instant;
@ -903,7 +949,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb4 collate utf8mb4_german2_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb4 collate utf8mb4_german2_ci,
algorithm=instant;
@ -920,7 +966,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf8mb3 collate utf8mb3_unicode_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf8mb3 collate utf8mb3_unicode_ci,
algorithm=instant;
@ -937,7 +983,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset latin1 collate latin1_general_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset latin1 collate latin1_general_ci,
algorithm=instant;
@ -954,7 +1000,7 @@ algorithm=instant;
alter table tmp
modify b varchar(50) charset utf16 collate utf16_german2_ci,
algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table tmp
modify c varchar(50) charset utf16 collate utf16_german2_ci,
algorithm=instant;
@ -1827,3 +1873,48 @@ CREATE TABLE t1 (a VARCHAR(1), UNIQUE(a)) ENGINE=InnoDB;
ALTER TABLE t1 MODIFY a INT, ADD b INT, ADD UNIQUE (b), ALGORITHM=INSTANT;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
DROP TABLE t1;
#
# MDEV-17301 Change of COLLATE unnecessarily requires ALGORITHM=COPY
#
create table t (
a char(10) collate latin1_general_ci primary key,
b char(10) collate latin1_general_ci,
c char(10) collate latin1_general_ci,
unique key b_key(b)
) engine=innodb;
insert into t values
('aaa', 'aaa', 'aaa'), ('ccc', 'ccc', 'ccc'), ('bbb', 'bbb', 'bbb');
alter table t modify a char(10) collate latin1_general_cs, algorithm=inplace;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify b char(10) collate latin1_general_cs, algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table t modify b char(10) collate latin1_general_cs, algorithm=nocopy;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify c char(10) collate latin1_general_cs, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
drop table t;
create table t (
a varchar(10) collate latin1_general_ci primary key,
b varchar(10) collate latin1_general_ci,
c varchar(10) collate latin1_general_ci,
unique key b_key(b)
) engine=innodb;
insert into t values
('aaa', 'aaa', 'aaa'), ('ccc', 'ccc', 'ccc'), ('bbb', 'bbb', 'bbb');
alter table t modify a varchar(10) collate latin1_general_cs, algorithm=inplace;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY
alter table t modify b varchar(10) collate latin1_general_cs, algorithm=instant;
ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY
alter table t modify b varchar(10) collate latin1_general_cs, algorithm=nocopy;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
alter table t modify c varchar(10) collate latin1_general_cs, algorithm=instant;
check table t;
Table Op Msg_type Msg_text
test.t check status OK
drop table t;

View File

@ -321,6 +321,67 @@ alter table boundary_255
drop table boundary_255;
create table t (
a char(10) collate utf8mb3_general_ci,
b char(70) collate utf8mb3_general_ci,
c char(100) collate utf8mb3_general_ci,
aa char(10) collate utf8mb3_general_ci unique,
bb char(70) collate utf8mb3_general_ci unique,
cc char(100) collate utf8mb3_general_ci unique,
d char(10) collate utf8mb3_general_ci,
dd char(10) collate utf8mb3_general_ci unique
) engine=innodb;
insert into t values
(repeat('a', 10), repeat('a', 70), repeat('a', 100),
repeat('a', 10), repeat('a', 70), repeat('a', 100),
repeat('a', 10), repeat('a', 10)
);
if ($row_format != 'redundant') {
alter table t modify a char(10) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify b char(70) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify c char(100) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify aa char(10) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify bb char(70) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify cc char(100) collate utf8mb4_general_ci, algorithm=instant;
check table t;
alter table t modify d char(10) collate utf8mb4_spanish_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify dd char(10) collate utf8mb4_spanish_ci, algorithm=instant;
}
if ($row_format == 'redundant') {
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify a char(10) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify b char(70) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify c char(100) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify aa char(10) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify bb char(70) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify cc char(100) collate utf8mb4_general_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify d char(10) collate utf8mb4_spanish_ci, algorithm=instant;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify dd char(10) collate utf8mb4_spanish_ci, algorithm=instant;
}
select * from t;
drop table t;
create table fully_compatible (
id int auto_increment unique key,
from_charset char(255),
@ -604,3 +665,53 @@ CREATE TABLE t1 (a VARCHAR(1), UNIQUE(a)) ENGINE=InnoDB;
ALTER TABLE t1 MODIFY a INT, ADD b INT, ADD UNIQUE (b), ALGORITHM=INSTANT;
DROP TABLE t1;
--echo #
--echo # MDEV-17301 Change of COLLATE unnecessarily requires ALGORITHM=COPY
--echo #
create table t (
a char(10) collate latin1_general_ci primary key,
b char(10) collate latin1_general_ci,
c char(10) collate latin1_general_ci,
unique key b_key(b)
) engine=innodb;
insert into t values
('aaa', 'aaa', 'aaa'), ('ccc', 'ccc', 'ccc'), ('bbb', 'bbb', 'bbb');
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify a char(10) collate latin1_general_cs, algorithm=inplace;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify b char(10) collate latin1_general_cs, algorithm=instant;
alter table t modify b char(10) collate latin1_general_cs, algorithm=nocopy;
check table t;
alter table t modify c char(10) collate latin1_general_cs, algorithm=instant;
check table t;
drop table t;
create table t (
a varchar(10) collate latin1_general_ci primary key,
b varchar(10) collate latin1_general_ci,
c varchar(10) collate latin1_general_ci,
unique key b_key(b)
) engine=innodb;
insert into t values
('aaa', 'aaa', 'aaa'), ('ccc', 'ccc', 'ccc'), ('bbb', 'bbb', 'bbb');
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify a varchar(10) collate latin1_general_cs, algorithm=inplace;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t modify b varchar(10) collate latin1_general_cs, algorithm=instant;
alter table t modify b varchar(10) collate latin1_general_cs, algorithm=nocopy;
check table t;
alter table t modify c varchar(10) collate latin1_general_cs, algorithm=instant;
check table t;
drop table t;

View File

@ -7073,36 +7073,40 @@ int Field_str::store(double nr)
return store(buff, (uint)length, &my_charset_numeric);
}
bool Field_longstr::
csinfo_change_allows_instant_alter(const Create_field *to) const
uint Field_longstr::
is_equal_for_different_charsets(const Column_definition &to) const
{
Charset cs(field_charset);
const bool part_of_a_key= !to->field->part_of_key.is_clear_all();
return part_of_a_key ?
cs.encoding_and_order_allow_reinterpret_as(to->charset) :
cs.encoding_allows_reinterpret_as(to->charset);
}
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)
{
DBUG_ASSERT(!compression_method());
if (new_field->type_handler() != type_handler())
return IS_EQUAL_NO;
if (new_field->length < max_display_length())
return IS_EQUAL_NO;
if (new_field->char_length < char_length())
return IS_EQUAL_NO;
if (!csinfo_change_allows_instant_alter(new_field))
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;
if (new_field->length == max_display_length())
return new_field->charset == field_charset
? IS_EQUAL_YES : IS_EQUAL_PACK_LENGTH;
return IS_EQUAL_NO;
return IS_EQUAL_YES;
}
@ -7936,6 +7940,20 @@ 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)
{
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)
@ -7944,24 +7962,26 @@ uint Field_varstring::is_equal(Create_field *new_field)
return IS_EQUAL_NO;
if (!new_field->compression_method() != !compression_method())
return IS_EQUAL_NO;
if (!csinfo_change_allows_instant_alter(new_field))
if (new_field->type_handler() != type_handler())
return IS_EQUAL_NO;
const Type_handler *new_type_handler= new_field->type_handler();
if (new_type_handler == type_handler())
if (new_field->charset != field_charset)
{
if (new_field->length == field_length)
return new_field->charset == field_charset
? IS_EQUAL_YES : IS_EQUAL_PACK_LENGTH;
if (field_length <= 127 ||
new_field->length <= 255 ||
field_length > 255 ||
(table->file->ha_table_flags() & HA_EXTENDED_TYPES_CONVERSION))
return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer length
if (!supports_such_enlargement(this, new_field))
return IS_EQUAL_NO;
return is_equal_for_different_charsets(*new_field);
}
return IS_EQUAL_NO;
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;
}
@ -8728,25 +8748,16 @@ uint Field_blob::max_packed_col_length(uint max_length)
uint Field_blob::is_equal(Create_field *new_field)
{
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 (!csinfo_change_allows_instant_alter(new_field))
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_PACK_LENGTH;
}
return is_equal_for_different_charsets(*new_field);
return IS_EQUAL_YES;
}
@ -11325,4 +11336,4 @@ void Field_blob::print_key_value(String *out, uint32 length)
void Field::print_key_value_binary(String *out, const uchar* key, uint32 length)
{
out->append_semi_hex((const char*)key, length, charset());
}
}

View File

@ -1928,7 +1928,8 @@ protected:
CHARSET_INFO *cs, size_t nchars);
String *uncompress(String *val_buffer, String *val_ptr,
const uchar *from, uint from_length);
bool csinfo_change_allows_instant_alter(const Create_field *to) const;
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,

View File

@ -354,6 +354,14 @@
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

@ -167,7 +167,7 @@ public:
*/
LEX_CSTRING collation_specific_name() const;
bool encoding_allows_reinterpret_as(CHARSET_INFO *cs) const;
bool encoding_and_order_allow_reinterpret_as(CHARSET_INFO *cs) const;
bool eq_collation_specific_names(CHARSET_INFO *cs) const;
};

View File

@ -6568,15 +6568,19 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
((Field_varstring *) old_field)->length_bytes);
}
uint is_equal= key_part->field->is_equal(new_field);
if (key_part->length == old_field_len &&
key_part->length < new_part->length &&
(key_part->field->is_equal((Create_field *) new_field) ==
IS_EQUAL_PACK_LENGTH))
(is_equal == IS_EQUAL_PACK_LENGTH ||
is_equal == IS_EQUAL_WITH_REINTERPRET_COMPATIBLE_CHARSET))
{
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;
}
/*
@ -6598,6 +6602,40 @@ 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.
@ -6735,7 +6773,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
Check if type of column has changed to some incompatible type.
*/
uint is_equal= field->is_equal(new_field);
switch (is_equal)
switch (process_is_equal_result_for_key_parts(is_equal, field, new_field))
{
case IS_EQUAL_NO:
/* New column type is incompatible with old one. */

View File

@ -8363,20 +8363,10 @@ Charset::encoding_allows_reinterpret_as(const CHARSET_INFO *cs) const
bool
Charset::encoding_and_order_allow_reinterpret_as(CHARSET_INFO *cs) const
Charset::eq_collation_specific_names(CHARSET_INFO *cs) const
{
/*
Test quickly if we have two exactly equal CHARSET_INFO pointers.
This also handles a special case with my_charset_bin:
it does not have a collation name specific part in CHARSET_INFO::name,
which is just "binary" (without a character set name prefix),
so the code with collation_specific_name() below won't work for it.
*/
if (m_charset == cs)
return true;
if (!encoding_allows_reinterpret_as(cs))
return false;
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

@ -9120,14 +9120,20 @@ innobase_rename_or_enlarge_column_try(
DBUG_ASSERT(col->len <= len);
#ifdef UNIV_DEBUG
ut_ad(col->mbminlen <= col->mbmaxlen);
switch (mtype) {
case DATA_MYSQL:
if (!(prtype & DATA_BINARY_TYPE) || user_table->not_redundant()
|| col->mbminlen != col->mbmaxlen) {
/* NOTE: we could allow this when !(prtype &
DATA_BINARY_TYPE) and ROW_FORMAT is not REDUNDANT and
mbminlen<mbmaxlen. That is, we treat a UTF-8 CHAR(n)
column somewhat like a VARCHAR. */
break;
}
/* fall through */
case DATA_FIXBINARY:
case DATA_CHAR:
case DATA_MYSQL:
/* NOTE: we could allow this when !(prtype & DATA_BINARY_TYPE)
and ROW_FORMAT is not REDUNDANT and mbminlen<mbmaxlen.
That is, we treat a UTF-8 CHAR(n) column somewhat like
a VARCHAR. */
ut_ad(col->len == len);
break;
case DATA_BINARY: