summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2019-06-14 12:18:49 +0300
committerEugene Kosov <claprix@yandex.ru>2019-06-22 03:53:00 +0300
commitb6e88535d42d01ab6c566967159d1b4c8fd0fa11 (patch)
tree126642a757db72f89788bec10cfb1c1be5f42772
parente9a692fe1ecd82e0812f4986a0010ca0db9295b7 (diff)
downloadmariadb-git-b6e88535d42d01ab6c566967159d1b4c8fd0fa11.tar.gz
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.
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_charset,redundant.rdiff49
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_charset.result113
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_charset.test111
-rw-r--r--sql/field.cc97
-rw-r--r--sql/field.h3
-rw-r--r--sql/sql_priv.h8
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_table.cc44
-rw-r--r--sql/sql_type.cc14
-rw-r--r--storage/innobase/handler/handler0alter.cc16
10 files changed, 377 insertions, 80 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_charset,redundant.rdiff b/mysql-test/suite/innodb/r/instant_alter_charset,redundant.rdiff
index d7d2a32d742..22b7e46ea9c 100644
--- a/mysql-test/suite/innodb/r/instant_alter_charset,redundant.rdiff
+++ b/mysql-test/suite/innodb/r/instant_alter_charset,redundant.rdiff
@@ -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
diff --git a/mysql-test/suite/innodb/r/instant_alter_charset.result b/mysql-test/suite/innodb/r/instant_alter_charset.result
index 2e278ac54f4..be15b02a8c6 100644
--- a/mysql-test/suite/innodb/r/instant_alter_charset.result
+++ b/mysql-test/suite/innodb/r/instant_alter_charset.result
@@ -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;
diff --git a/mysql-test/suite/innodb/t/instant_alter_charset.test b/mysql-test/suite/innodb/t/instant_alter_charset.test
index 8259689a139..b6e45cb6924 100644
--- a/mysql-test/suite/innodb/t/instant_alter_charset.test
+++ b/mysql-test/suite/innodb/t/instant_alter_charset.test
@@ -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;
diff --git a/sql/field.cc b/sql/field.cc
index 1c874c1021a..761e2c66641 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -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))
- 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;
- if (new_field->length == max_display_length())
- return new_field->charset == field_charset
- ? IS_EQUAL_YES : IS_EQUAL_PACK_LENGTH;
+ return is_equal_for_different_charsets(*new_field);
+ }
- return IS_EQUAL_NO;
+ if (new_field->length != max_display_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->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());
-} \ No newline at end of file
+}
diff --git a/sql/field.h b/sql/field.h
index 1aeca8a34c9..8c46633d550 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -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,
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 0d1c9881c17..0b06985f431 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -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
{
diff --git a/sql/sql_string.h b/sql/sql_string.h
index f21f23e42ef..10af5a9426f 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -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;
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 8a8d464845c..b6cc3a4290e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -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;
}
/*
@@ -6599,6 +6603,40 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
}
/**
+ 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. */
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index fc33b6d1427..446e753e006 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -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);
}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 39d97f8f8af..e4f5a04f668 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -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: