Skip to content

Commit efae374

Browse files
committed
MDEV-26203 CREATE INDEX may enforce incorrect maximum column length
ha_innobase::prepare_inplace_alter_table(): Unless the table is being rebuilt, determine the maximum column length based on the current ROW_FORMAT of the table. When TABLE_SHARE (and the .frm file) contains no explicit ROW_FORMAT, InnoDB table creation or rebuild will use innodb_default_row_format. Based on mysql/mysql-server@3287d33
1 parent 8ad6971 commit efae374

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

mysql-test/suite/innodb/r/default_row_format_alter.result

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ INSERT INTO t1 VALUES (1, 'abc');
2323
SHOW TABLE STATUS LIKE 't1';
2424
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
2525
t1 InnoDB # Compact # # # # # # NULL # # NULL latin1_swedish_ci NULL
26+
CREATE TABLE t2 (b VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL) ENGINE=InnoDB;
2627
SET GLOBAL innodb_default_row_format = DYNAMIC;
2728
ALTER TABLE t1 DROP PRIMARY KEY, ADD COLUMN c INT PRIMARY KEY;
2829
# Here we expect DYNAMIC because there is no explicit ROW_FORMAT and the
@@ -31,6 +32,10 @@ SHOW TABLE STATUS LIKE 't1';
3132
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
3233
t1 InnoDB # Dynamic # # # # # # NULL # # NULL latin1_swedish_ci NULL
3334
DROP TABLE t1;
35+
ALTER TABLE t2 ADD INDEX(b);
36+
ERROR HY000: Index column size too large. The maximum column size is 767 bytes
37+
ALTER TABLE t2 FORCE, ADD INDEX(b);
38+
DROP TABLE t2;
3439
####################################
3540
# Check the row_format effect on ALTER, ALGORITHM=COPY
3641
SET GLOBAL innodb_default_row_format = REDUNDANT;
@@ -39,6 +44,7 @@ INSERT INTO t1 VALUES (1, REPEAT('abc',1000));
3944
SHOW TABLE STATUS LIKE 't1';
4045
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4146
t1 InnoDB # Redundant # # # # # # NULL # # NULL latin1_swedish_ci NULL
47+
CREATE TABLE t2 (b VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL) ENGINE=InnoDB;
4248
SET GLOBAL innoDB_default_row_format = COMPACT;
4349
ALTER TABLE t1 ADD COLUMN c2 BLOB, ALGORITHM=COPY;
4450
# Because of ALGORITHM=COPY, there is TABLE REBUILD and the table isn't
@@ -47,9 +53,18 @@ SHOW TABLE STATUS LIKE 't1';
4753
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
4854
t1 InnoDB # Compact # # # # # # NULL # # NULL latin1_swedish_ci NULL
4955
DROP TABLE t1;
56+
ALTER TABLE t2 ADD INDEX(b);
57+
ERROR HY000: Index column size too large. The maximum column size is 767 bytes
58+
ALTER TABLE t2 FORCE, ADD INDEX(b);
59+
ERROR HY000: Index column size too large. The maximum column size is 767 bytes
60+
SET GLOBAL innodb_default_row_format = DYNAMIC;
61+
ALTER TABLE t2 ADD INDEX(b);
62+
ERROR HY000: Index column size too large. The maximum column size is 767 bytes
63+
ALTER TABLE t2 FORCE, ADD INDEX(b);
64+
DROP TABLE t2;
5065

5166
###################################
52-
# Check the row_format effect on ALTER, ALGORITH=COPY on
67+
# Check the row_format effect on ALTER, ALGORITHM=COPY on
5368
# create table with explicit row_format
5469
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=INNODB;
5570
INSERT INTO t1 VALUES (1, REPEAT('abc',1000));

mysql-test/suite/innodb/t/default_row_format_alter.test

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ SET @row_format = @@GLOBAL.innodb_default_row_format;
55
--echo ####################################
66
--echo # Check if table rebuilding alter isn't affect if table is created
77
--echo # with explicit row_format
8-
eval CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=INNODB;
8+
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=INNODB;
99
INSERT INTO t1 VALUES (1, 'abc');
1010
--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 #
1111
SHOW TABLE STATUS LIKE 't1';
@@ -22,12 +22,14 @@ DROP TABLE t1;
2222
--echo # Check if table rebuilding alter is affected when there is no
2323
--echo # row_format specified at CREATE TABLE.
2424
SET GLOBAL innodb_default_row_format = COMPACT;
25-
eval CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=INNODB;
25+
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=INNODB;
2626
INSERT INTO t1 VALUES (1, 'abc');
2727

2828
--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 #
2929
SHOW TABLE STATUS LIKE 't1';
3030

31+
CREATE TABLE t2 (b VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL) ENGINE=InnoDB;
32+
3133
SET GLOBAL innodb_default_row_format = DYNAMIC;
3234
ALTER TABLE t1 DROP PRIMARY KEY, ADD COLUMN c INT PRIMARY KEY;
3335

@@ -37,15 +39,22 @@ ALTER TABLE t1 DROP PRIMARY KEY, ADD COLUMN c INT PRIMARY KEY;
3739
SHOW TABLE STATUS LIKE 't1';
3840
DROP TABLE t1;
3941

42+
--error ER_INDEX_COLUMN_TOO_LONG
43+
ALTER TABLE t2 ADD INDEX(b);
44+
ALTER TABLE t2 FORCE, ADD INDEX(b);
45+
DROP TABLE t2;
46+
4047
--echo ####################################
4148
--echo # Check the row_format effect on ALTER, ALGORITHM=COPY
4249
SET GLOBAL innodb_default_row_format = REDUNDANT;
43-
eval CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=INNODB;
50+
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ENGINE=INNODB;
4451
INSERT INTO t1 VALUES (1, REPEAT('abc',1000));
4552

4653
--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 #
4754
SHOW TABLE STATUS LIKE 't1';
4855

56+
CREATE TABLE t2 (b VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL) ENGINE=InnoDB;
57+
4958
SET GLOBAL innoDB_default_row_format = COMPACT;
5059
ALTER TABLE t1 ADD COLUMN c2 BLOB, ALGORITHM=COPY;
5160

@@ -55,11 +64,23 @@ ALTER TABLE t1 ADD COLUMN c2 BLOB, ALGORITHM=COPY;
5564
SHOW TABLE STATUS LIKE 't1';
5665
DROP TABLE t1;
5766

67+
--error ER_INDEX_COLUMN_TOO_LONG
68+
ALTER TABLE t2 ADD INDEX(b);
69+
--error ER_INDEX_COLUMN_TOO_LONG
70+
ALTER TABLE t2 FORCE, ADD INDEX(b);
71+
72+
SET GLOBAL innodb_default_row_format = DYNAMIC;
73+
--error ER_INDEX_COLUMN_TOO_LONG
74+
ALTER TABLE t2 ADD INDEX(b);
75+
ALTER TABLE t2 FORCE, ADD INDEX(b);
76+
77+
DROP TABLE t2;
78+
5879
--echo
5980
--echo ###################################
60-
--echo # Check the row_format effect on ALTER, ALGORITH=COPY on
81+
--echo # Check the row_format effect on ALTER, ALGORITHM=COPY on
6182
--echo # create table with explicit row_format
62-
eval CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=INNODB;
83+
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=INNODB;
6384
INSERT INTO t1 VALUES (1, REPEAT('abc',1000));
6485

6586
--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 #
@@ -80,7 +101,7 @@ DROP TABLE t1;
80101
--echo # Check row_format on ALTER ALGORITHM=INPLACE
81102
SET GLOBAL innodb_default_row_format=COMPACT;
82103

83-
eval CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT, KEY k1(b(10))) ENGINE=INNODB;
104+
CREATE TABLE t1 (a INT PRIMARY KEY, b TEXT, KEY k1(b(10))) ENGINE=INNODB;
84105
INSERT INTO t1 VALUES (1, REPEAT('abc',1000));
85106

86107
--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 #

storage/innobase/handler/handler0alter.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5387,7 +5387,6 @@ ha_innobase::prepare_inplace_alter_table(
53875387
mem_heap_t* heap;
53885388
const char** col_names;
53895389
int error;
5390-
ulint max_col_len;
53915390
ulint add_autoinc_col_no = ULINT_UNDEFINED;
53925391
ulonglong autoinc_col_max_value = 0;
53935392
ulint fts_doc_col_no = ULINT_UNDEFINED;
@@ -5601,7 +5600,13 @@ ha_innobase::prepare_inplace_alter_table(
56015600
& 1U << DICT_TF_POS_DATA_DIR);
56025601
}
56035602

5604-
max_col_len = DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(info.flags());
5603+
5604+
/* ALGORITHM=INPLACE without rebuild (10.3+ ALGORITHM=NOCOPY)
5605+
must use the current ROW_FORMAT of the table. */
5606+
const ulint max_col_len = DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(
5607+
innobase_need_rebuild(ha_alter_info, this->table)
5608+
? info.flags()
5609+
: m_prebuilt->table->flags);
56055610

56065611
/* Check each index's column length to make sure they do not
56075612
exceed limit */

0 commit comments

Comments
 (0)