Skip to content

Commit 89041ce

Browse files
committed
Bug#22740093: ERROR 1071 (42000): SPECIFIED KEY WAS TOO LONG
ERROR WHILE DROPPING INDEX IN 5.7 This bug concerns the check of index prefix lengths for TEXT type columns. These types of columns has a maximum length measured in bytes (e.g. 255 bytes for TINYTEXT). However the index prefix length specified in CREATE TABLE and ALTER TABLE statements is in characters. This gave separate buggy behavior for CREATE TABLE and ALTER TABLE: During CREATE TABLE, the index prefix length was only checked against storage engine maximum sizes, not the maximum size of the column (Create_field::key_length is still 0 when the check was attempted). This e.g. meant that you could create a prefix index of 768 utf8mb4 characters for TINYTEXT columns even if the real maximum is 63 characters (255/4). (768 * 4 = 3072 is the InnoDB max index length). During ALTER TABLE, the check was broken for multibyte character sets as we multiplied the maximum size of each column with bytes_per_character one time too many. This e.g meant that at you could add an index of 252 utf8mb4 characters for TINYTEXT columns (63 * 4 = 252). This patch fixes the problem by comparing the index prefix length in bytes against the max column length in bytes. So for TINYTEXT, the maximum prefix is now 63 regardless of whether CREATE TABLE or ALTER TABLE is used to create the index (assuming a 4 byte character set is used).
1 parent ef09049 commit 89041ce

12 files changed

+92
-17
lines changed

mysql-test/r/alter_table.result

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,8 @@ DROP TABLE t1;
14211421
DROP DATABASE IF EXISTS db1;
14221422
CREATE DATABASE db1 CHARACTER SET utf8;
14231423
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100)));
1424+
ERROR 42000: Specified key was too long; max key length is 255 bytes
1425+
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(85)));
14241426
ALTER TABLE db1.t1 ADD baz INT;
14251427
DROP DATABASE db1;
14261428
# Additional coverage for refactoring which is made as part
@@ -3497,3 +3499,28 @@ t1 CREATE TABLE `t1` (
34973499
PRIMARY KEY (`fld1`)
34983500
) ENGINE=InnoDB DEFAULT CHARSET=utf8
34993501
DROP TABLE t1;
3502+
#
3503+
# Bug#22740093: ERROR 1071 (42000): SPECIFIED KEY WAS TOO LONG
3504+
# ERROR WHILE DROPPING INDEX IN 5.7
3505+
#
3506+
CREATE TABLE t1(id INT PRIMARY KEY,
3507+
name TINYTEXT,
3508+
KEY nameloc (name(64))
3509+
) DEFAULT CHARSET=utf8mb4;
3510+
ERROR 42000: Specified key was too long; max key length is 255 bytes
3511+
CREATE TABLE t1(id INT PRIMARY KEY,
3512+
name TINYTEXT,
3513+
KEY nameloc (name(63))
3514+
) DEFAULT CHARSET=utf8mb4;
3515+
ALTER TABLE t1 FORCE;
3516+
ALTER TABLE t1 ADD INDEX idx (name(64), id);
3517+
ERROR 42000: Specified key was too long; max key length is 255 bytes
3518+
ALTER TABLE t1 ADD INDEX idx (name(63), id);
3519+
DROP TABLE t1;
3520+
CREATE TABLE t1(id INT PRIMARY KEY,
3521+
name TEXT,
3522+
KEY nameloc (name(64))
3523+
) DEFAULT CHARSET=utf8mb4;
3524+
ALTER TABLE t1 MODIFY COLUMN name TINYTEXT;
3525+
ERROR 42000: Specified key was too long; max key length is 255 bytes
3526+
DROP TABLE t1;

mysql-test/r/ctype_utf8.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,7 +2095,7 @@ CREATE TABLE t1 (
20952095
clipid INT NOT NULL,
20962096
Tape TINYTEXT,
20972097
PRIMARY KEY (clipid),
2098-
KEY tape(Tape(255))
2098+
KEY tape(Tape(85))
20992099
) CHARACTER SET=utf8;
21002100
ALTER TABLE t1 ADD mos TINYINT DEFAULT 0 AFTER clipid;
21012101
SHOW CREATE TABLE t1;
@@ -2105,7 +2105,7 @@ t1 CREATE TABLE `t1` (
21052105
`mos` tinyint(4) DEFAULT '0',
21062106
`Tape` tinytext,
21072107
PRIMARY KEY (`clipid`),
2108-
KEY `tape` (`Tape`(255))
2108+
KEY `tape` (`Tape`(85))
21092109
) ENGINE=MyISAM DEFAULT CHARSET=utf8
21102110
DROP TABLE t1;
21112111
DROP TABLE IF EXISTS t1;

mysql-test/r/ctype_utf8mb4.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,7 @@ PRIMARY KEY (clipid),
22442244
KEY tape(Tape(255))
22452245
) CHARACTER SET=utf8mb4;
22462246
Warnings:
2247-
Warning 1071 Specified key was too long; max key length is 1000 bytes
2247+
Warning 1071 Specified key was too long; max key length is 255 bytes
22482248
ALTER TABLE t1 ADD mos TINYINT DEFAULT 0 AFTER clipid;
22492249
SHOW CREATE TABLE t1;
22502250
Table Create Table
@@ -2253,7 +2253,7 @@ t1 CREATE TABLE `t1` (
22532253
`mos` tinyint(4) DEFAULT '0',
22542254
`Tape` tinytext,
22552255
PRIMARY KEY (`clipid`),
2256-
KEY `tape` (`Tape`(250))
2256+
KEY `tape` (`Tape`(63))
22572257
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
22582258
DROP TABLE t1;
22592259
SET sql_mode = default;

mysql-test/r/ctype_utf8mb4_innodb.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,7 +2204,7 @@ PRIMARY KEY (clipid),
22042204
KEY tape(Tape(255))
22052205
) CHARACTER SET=utf8mb4 ENGINE InnoDB;
22062206
Warnings:
2207-
Warning 1071 Specified key was too long; max key length is 767 bytes
2207+
Warning 1071 Specified key was too long; max key length is 255 bytes
22082208
ALTER TABLE t1 ADD mos TINYINT DEFAULT 0 AFTER clipid;
22092209
SHOW CREATE TABLE t1;
22102210
Table Create Table
@@ -2213,7 +2213,7 @@ t1 CREATE TABLE `t1` (
22132213
`mos` tinyint(4) DEFAULT '0',
22142214
`Tape` tinytext,
22152215
PRIMARY KEY (`clipid`),
2216-
KEY `tape` (`Tape`(191))
2216+
KEY `tape` (`Tape`(63))
22172217
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
22182218
DROP TABLE t1;
22192219
SET sql_mode = default;

mysql-test/r/ctype_utf8mb4_myisam.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2201,7 +2201,7 @@ PRIMARY KEY (clipid),
22012201
KEY tape(Tape(255))
22022202
) CHARACTER SET=utf8mb4 ENGINE MyISAM;
22032203
Warnings:
2204-
Warning 1071 Specified key was too long; max key length is 1000 bytes
2204+
Warning 1071 Specified key was too long; max key length is 255 bytes
22052205
ALTER TABLE t1 ADD mos TINYINT DEFAULT 0 AFTER clipid;
22062206
SHOW CREATE TABLE t1;
22072207
Table Create Table
@@ -2210,7 +2210,7 @@ t1 CREATE TABLE `t1` (
22102210
`mos` tinyint(4) DEFAULT '0',
22112211
`Tape` tinytext,
22122212
PRIMARY KEY (`clipid`),
2213-
KEY `tape` (`Tape`(250))
2213+
KEY `tape` (`Tape`(63))
22142214
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
22152215
DROP TABLE t1;
22162216
SET sql_mode = default;

mysql-test/suite/parts/inc/partition_blob.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ eval create table t2 (a blob not null, primary key(a(767))) engine=$engine
2222
partition by key (a) partitions 30;
2323

2424
--error ER_BLOB_FIELD_IN_PART_FUNC_ERROR
25-
eval create table t2 (a tinyblob not null, primary key(a(767))) engine=$engine
25+
eval create table t2 (a tinyblob not null, primary key(a(255))) engine=$engine
2626
partition by key (a) partitions 30;
2727

2828
--error ER_BLOB_FIELD_IN_PART_FUNC_ERROR

mysql-test/suite/parts/inc/partition_text.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ partition pa4 max_rows=40 min_rows=2);
1818
#drop table t1;
1919

2020
--error ER_BLOB_FIELD_IN_PART_FUNC_ERROR
21-
eval create table t2 (a tinytext not null, primary key(a(767))) engine=$engine
21+
eval create table t2 (a tinytext not null, primary key(a(255))) engine=$engine
2222
partition by key (a) partitions 30;
2323

2424
--error ER_BLOB_FIELD_IN_PART_FUNC_ERROR

mysql-test/suite/parts/r/partition_char_innodb.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ ERROR HY000: A BLOB field is not allowed in partition function
733733
create table t2 (a blob not null, primary key(a(767))) engine='InnoDB'
734734
partition by key (a) partitions 30;
735735
ERROR HY000: A BLOB field is not allowed in partition function
736-
create table t2 (a tinyblob not null, primary key(a(767))) engine='InnoDB'
736+
create table t2 (a tinyblob not null, primary key(a(255))) engine='InnoDB'
737737
partition by key (a) partitions 30;
738738
ERROR HY000: A BLOB field is not allowed in partition function
739739
create table t2 (a mediumblob not null, primary key(a(767))) engine='InnoDB'
@@ -750,7 +750,7 @@ partition pa2 max_rows=30 min_rows=3,
750750
partition pa3 max_rows=30 min_rows=4,
751751
partition pa4 max_rows=40 min_rows=2);
752752
ERROR HY000: A BLOB field is not allowed in partition function
753-
create table t2 (a tinytext not null, primary key(a(767))) engine='InnoDB'
753+
create table t2 (a tinytext not null, primary key(a(255))) engine='InnoDB'
754754
partition by key (a) partitions 30;
755755
ERROR HY000: A BLOB field is not allowed in partition function
756756
create table t2 (a mediumtext not null, primary key(a(767))) engine='InnoDB'

mysql-test/suite/parts/r/partition_char_myisam.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ ERROR HY000: A BLOB field is not allowed in partition function
733733
create table t2 (a blob not null, primary key(a(767))) engine='MyISAM'
734734
partition by key (a) partitions 30;
735735
ERROR HY000: A BLOB field is not allowed in partition function
736-
create table t2 (a tinyblob not null, primary key(a(767))) engine='MyISAM'
736+
create table t2 (a tinyblob not null, primary key(a(255))) engine='MyISAM'
737737
partition by key (a) partitions 30;
738738
ERROR HY000: A BLOB field is not allowed in partition function
739739
create table t2 (a mediumblob not null, primary key(a(767))) engine='MyISAM'
@@ -750,7 +750,7 @@ partition pa2 max_rows=30 min_rows=3,
750750
partition pa3 max_rows=30 min_rows=4,
751751
partition pa4 max_rows=40 min_rows=2);
752752
ERROR HY000: A BLOB field is not allowed in partition function
753-
create table t2 (a tinytext not null, primary key(a(767))) engine='MyISAM'
753+
create table t2 (a tinytext not null, primary key(a(255))) engine='MyISAM'
754754
partition by key (a) partitions 30;
755755
ERROR HY000: A BLOB field is not allowed in partition function
756756
create table t2 (a mediumtext not null, primary key(a(767))) engine='MyISAM'

mysql-test/t/alter_table.test

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,9 @@ DROP DATABASE IF EXISTS db1;
11771177
--enable_warnings
11781178

11791179
CREATE DATABASE db1 CHARACTER SET utf8;
1180+
--error ER_TOO_LONG_KEY
11801181
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100)));
1182+
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(85)));
11811183
ALTER TABLE db1.t1 ADD baz INT;
11821184

11831185
DROP DATABASE db1;
@@ -2804,3 +2806,48 @@ let $test_dir =
28042806
--list_files $test_dir `#sql-*.frm`
28052807

28062808
DROP TABLE t1;
2809+
2810+
--echo #
2811+
--echo # Bug#22740093: ERROR 1071 (42000): SPECIFIED KEY WAS TOO LONG
2812+
--echo # ERROR WHILE DROPPING INDEX IN 5.7
2813+
--echo #
2814+
2815+
# Before you were allowed to create a prefix key for TEXT columns
2816+
# which were larger than the column length. The column length
2817+
# for TINYBLOB is 255 bytes, while prefix length is in characters.
2818+
--error ER_TOO_LONG_KEY
2819+
CREATE TABLE t1(id INT PRIMARY KEY,
2820+
name TINYTEXT,
2821+
KEY nameloc (name(64))
2822+
) DEFAULT CHARSET=utf8mb4;
2823+
2824+
# 63 characters of 4 bytes each fit in 255 bytes.
2825+
CREATE TABLE t1(id INT PRIMARY KEY,
2826+
name TINYTEXT,
2827+
KEY nameloc (name(63))
2828+
) DEFAULT CHARSET=utf8mb4;
2829+
2830+
# Check that we can rebuild the table without issue
2831+
ALTER TABLE t1 FORCE;
2832+
2833+
# Also check ALTER TABLE
2834+
--error ER_TOO_LONG_KEY
2835+
ALTER TABLE t1 ADD INDEX idx (name(64), id);
2836+
ALTER TABLE t1 ADD INDEX idx (name(63), id);
2837+
DROP TABLE t1;
2838+
2839+
# Check that we can create a table with a prefix index of
2840+
# 64 4-byte characters for a TEXT column.
2841+
2842+
# 64 characters of 4 bytes each fit in 65535 bytes.
2843+
CREATE TABLE t1(id INT PRIMARY KEY,
2844+
name TEXT,
2845+
KEY nameloc (name(64))
2846+
) DEFAULT CHARSET=utf8mb4;
2847+
2848+
# Check ALTER TABLE where we change the type of the
2849+
# base column, reducing max field length, keeping the
2850+
# length of the prefix key the same.
2851+
--error ER_TOO_LONG_KEY
2852+
ALTER TABLE t1 MODIFY COLUMN name TINYTEXT;
2853+
DROP TABLE t1;

0 commit comments

Comments
 (0)