Skip to content

Commit fdbdce7

Browse files
author
Aditya A
committed
Bug #26390736 THE FIELD TABLE_NAME (VARCHAR(64)) FROM
MYSQL.INNODB_TABLE_STATS CAN OVERFLOW. In mysql.innodb_index_stats and mysql.innodb_table_stats tables the table name column didn't take into consideration partition names which can be more than varchar(64). FIX --- 1. Changed the column length to 199 because the table name can contain (table_name)#P#(partition_name)#SP#(subpartition_name) with each identifier being 64 chars and taking the special symbolsadded to recognize it is a partitioned table ,the length comes out to be 199. 2. Returning error in few cases where the length exceeds the file system name limit. This also fixes Bug#26953573 I_MAIN.PARTITION_INNODB_CRASH FAILING IN WEEKLY-5.7 3. User need to do a mysql_upgrade to modify the length of the system tables. 4. If the user doesn't run the the mysql_upgrade the fix will not work ,but a warning message will be generated to remind the user to call mysql_upgrdae. 5. This fix is for mysql-5.7 only , since 8.0+ has already updated its system tables with this change. 6. innodb_index_stats has a primary key which is defined as PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`) and the PRIMARY KEY defined on innodb_table_stats is PRIMARY KEY (`database_name`,`table_name`) Since we are increasing the length of "table_name" column the index size increases ,which will cross the limit of 768 Bytes defined for a 4k page size. Innodb can usually support key size which is half of the page size. While estimating the maximum key size supported we usually take the case of secondary indexes ( which also contains the primary key) and estimate the key_length of about 1/4 of page size. In this case there is only primary key defined on these tables and innodb can support this index size. Therefore we have defined these two tables as system tables and the server whitelists them and skips the index length check on them. 7. In server we have introduced a function ha_check_if_supported_system_table() will check if these tables are whitelisted ,and skip the key index length check. [#rb 18858 Reviewed By Deb,Dyre]
1 parent bb1d250 commit fdbdce7

19 files changed

+443
-93
lines changed

mysql-test/suite/funcs_1/r/is_columns_mysql.result

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,13 @@ def mysql innodb_index_stats sample_size 7 NULL YES bigint NULL NULL 20 0 NULL N
9696
def mysql innodb_index_stats stat_description 8 NULL NO varchar 1024 3072 NULL NULL NULL utf8 utf8_bin varchar(1024) select,insert,update,references
9797
def mysql innodb_index_stats stat_name 5 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) PRI select,insert,update,references
9898
def mysql innodb_index_stats stat_value 6 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references
99-
def mysql innodb_index_stats table_name 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) PRI select,insert,update,references
99+
def mysql innodb_index_stats table_name 2 NULL NO varchar 199 597 NULL NULL NULL utf8 utf8_bin varchar(199) PRI select,insert,update,references
100100
def mysql innodb_table_stats clustered_index_size 5 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references
101101
def mysql innodb_table_stats database_name 1 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) PRI select,insert,update,references
102102
def mysql innodb_table_stats last_update 3 CURRENT_TIMESTAMP NO timestamp NULL NULL NULL NULL 0 NULL NULL timestamp on update CURRENT_TIMESTAMP select,insert,update,references
103103
def mysql innodb_table_stats n_rows 4 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references
104104
def mysql innodb_table_stats sum_of_other_index_sizes 6 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references
105-
def mysql innodb_table_stats table_name 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_bin varchar(64) PRI select,insert,update,references
105+
def mysql innodb_table_stats table_name 2 NULL NO varchar 199 597 NULL NULL NULL utf8 utf8_bin varchar(199) PRI select,insert,update,references
106106
def mysql ndb_binlog_index deletes 6 NULL NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references
107107
def mysql ndb_binlog_index epoch 3 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned PRI select,insert,update,references
108108
def mysql ndb_binlog_index File 2 NULL NO varchar 255 255 NULL NULL NULL latin1 latin1_swedish_ci varchar(255) select,insert,update,references
@@ -448,15 +448,15 @@ NULL mysql help_topic help_category_id smallint NULL NULL NULL NULL smallint(5)
448448
1.0000 mysql help_topic example text 65535 65535 utf8 utf8_general_ci text
449449
1.0000 mysql help_topic url text 65535 65535 utf8 utf8_general_ci text
450450
3.0000 mysql innodb_index_stats database_name varchar 64 192 utf8 utf8_bin varchar(64)
451-
3.0000 mysql innodb_index_stats table_name varchar 64 192 utf8 utf8_bin varchar(64)
451+
3.0000 mysql innodb_index_stats table_name varchar 199 597 utf8 utf8_bin varchar(199)
452452
3.0000 mysql innodb_index_stats index_name varchar 64 192 utf8 utf8_bin varchar(64)
453453
NULL mysql innodb_index_stats last_update timestamp NULL NULL NULL NULL timestamp
454454
3.0000 mysql innodb_index_stats stat_name varchar 64 192 utf8 utf8_bin varchar(64)
455455
NULL mysql innodb_index_stats stat_value bigint NULL NULL NULL NULL bigint(20) unsigned
456456
NULL mysql innodb_index_stats sample_size bigint NULL NULL NULL NULL bigint(20) unsigned
457457
3.0000 mysql innodb_index_stats stat_description varchar 1024 3072 utf8 utf8_bin varchar(1024)
458458
3.0000 mysql innodb_table_stats database_name varchar 64 192 utf8 utf8_bin varchar(64)
459-
3.0000 mysql innodb_table_stats table_name varchar 64 192 utf8 utf8_bin varchar(64)
459+
3.0000 mysql innodb_table_stats table_name varchar 199 597 utf8 utf8_bin varchar(199)
460460
NULL mysql innodb_table_stats last_update timestamp NULL NULL NULL NULL timestamp
461461
NULL mysql innodb_table_stats n_rows bigint NULL NULL NULL NULL bigint(20) unsigned
462462
NULL mysql innodb_table_stats clustered_index_size bigint NULL NULL NULL NULL bigint(20) unsigned

mysql-test/suite/innodb_gis/r/create_spatial_index.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ CREATE SPATIAL INDEX idx2 ON t1(c1);
14011401
DROP TABLE t1;
14021402
CREATE TABLE mysql.innodb_table_stats (
14031403
database_name varchar(64) COLLATE utf8_bin NOT NULL,
1404-
table_name varchar(64) COLLATE utf8_bin NOT NULL,
1404+
table_name varchar(199) COLLATE utf8_bin NOT NULL,
14051405
last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
14061406
n_rows bigint(20) unsigned NOT NULL,
14071407
clustered_index_size bigint(20) unsigned NOT NULL,

mysql-test/suite/innodb_gis/t/create_spatial_index.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ CREATE SPATIAL INDEX idx2 ON t1(c1);
11651165
DROP TABLE t1;
11661166
CREATE TABLE mysql.innodb_table_stats (
11671167
database_name varchar(64) COLLATE utf8_bin NOT NULL,
1168-
table_name varchar(64) COLLATE utf8_bin NOT NULL,
1168+
table_name varchar(199) COLLATE utf8_bin NOT NULL,
11691169
last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
11701170
n_rows bigint(20) unsigned NOT NULL,
11711171
clustered_index_size bigint(20) unsigned NOT NULL,
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#
2+
# Bug26390736 THE FIELD TABLE_NAME (VARCHAR(64)) FROM MYSQL.INNODB_TABLE_STATS CAN OVERFLOW
3+
#
4+
show create table mysql.innodb_index_stats;
5+
Table Create Table
6+
innodb_index_stats CREATE TABLE `innodb_index_stats` (
7+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
8+
`table_name` varchar(199) COLLATE utf8_bin NOT NULL,
9+
`index_name` varchar(64) COLLATE utf8_bin NOT NULL,
10+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
11+
`stat_name` varchar(64) COLLATE utf8_bin NOT NULL,
12+
`stat_value` bigint(20) unsigned NOT NULL,
13+
`sample_size` bigint(20) unsigned DEFAULT NULL,
14+
`stat_description` varchar(1024) COLLATE utf8_bin NOT NULL,
15+
PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
16+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
17+
show create table mysql.innodb_table_stats;
18+
Table Create Table
19+
innodb_table_stats CREATE TABLE `innodb_table_stats` (
20+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
21+
`table_name` varchar(199) COLLATE utf8_bin NOT NULL,
22+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
23+
`n_rows` bigint(20) unsigned NOT NULL,
24+
`clustered_index_size` bigint(20) unsigned NOT NULL,
25+
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
26+
PRIMARY KEY (`database_name`,`table_name`)
27+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
28+
create table abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij (id int) engine=innodb
29+
partition by range (id)
30+
subpartition by hash(id) (
31+
partition pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij values less than (10) (
32+
subpartition subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij,
33+
subpartition s02
34+
),
35+
partition pmax VALUES LESS THAN MAXVALUE (
36+
subpartition pmax_sub1,
37+
subpartition pmax_sub2
38+
)
39+
);
40+
select table_name,LENGTH(table_name) from mysql.innodb_table_stats where LENGTH(table_name) = 199;
41+
table_name LENGTH(table_name)
42+
abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#p#pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#sp#subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij 199
43+
select table_name,LENGTH(table_name) from mysql.innodb_index_stats where LENGTH(table_name) = 199;
44+
table_name LENGTH(table_name)
45+
abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#p#pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#sp#subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij 199
46+
abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#p#pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#sp#subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij 199
47+
abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#p#pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij#sp#subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij 199
48+
drop table abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij;
49+
CALL mtr.add_suppression("Table mysql/innodb_table_stats has length mismatch in the column name table_name. Please run mysql_upgrade");
50+
CALL mtr.add_suppression("Table mysql/innodb_index_stats has length mismatch in the column name table_name. Please run mysql_upgrade");
51+
alter table mysql.innodb_table_stats modify table_name varchar(64);
52+
alter table mysql.innodb_index_stats modify table_name varchar(64);
53+
show create table mysql.innodb_index_stats;
54+
Table Create Table
55+
innodb_index_stats CREATE TABLE `innodb_index_stats` (
56+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
57+
`table_name` varchar(64) COLLATE utf8_bin NOT NULL,
58+
`index_name` varchar(64) COLLATE utf8_bin NOT NULL,
59+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
60+
`stat_name` varchar(64) COLLATE utf8_bin NOT NULL,
61+
`stat_value` bigint(20) unsigned NOT NULL,
62+
`sample_size` bigint(20) unsigned DEFAULT NULL,
63+
`stat_description` varchar(1024) COLLATE utf8_bin NOT NULL,
64+
PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
65+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
66+
show create table mysql.innodb_table_stats;
67+
Table Create Table
68+
innodb_table_stats CREATE TABLE `innodb_table_stats` (
69+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
70+
`table_name` varchar(64) COLLATE utf8_bin NOT NULL,
71+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
72+
`n_rows` bigint(20) unsigned NOT NULL,
73+
`clustered_index_size` bigint(20) unsigned NOT NULL,
74+
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
75+
PRIMARY KEY (`database_name`,`table_name`)
76+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
77+
mysql.columns_priv OK
78+
mysql.db OK
79+
mysql.engine_cost OK
80+
mysql.event OK
81+
mysql.func OK
82+
mysql.general_log OK
83+
mysql.gtid_executed OK
84+
mysql.help_category OK
85+
mysql.help_keyword OK
86+
mysql.help_relation OK
87+
mysql.help_topic OK
88+
mysql.innodb_index_stats OK
89+
mysql.innodb_table_stats OK
90+
mysql.ndb_binlog_index OK
91+
mysql.plugin OK
92+
mysql.proc OK
93+
mysql.procs_priv OK
94+
mysql.proxies_priv OK
95+
mysql.server_cost OK
96+
mysql.servers OK
97+
mysql.slave_master_info OK
98+
mysql.slave_relay_log_info OK
99+
mysql.slave_worker_info OK
100+
mysql.slow_log OK
101+
mysql.tables_priv OK
102+
mysql.time_zone OK
103+
mysql.time_zone_leap_second OK
104+
mysql.time_zone_name OK
105+
mysql.time_zone_transition OK
106+
mysql.time_zone_transition_type OK
107+
mysql.user OK
108+
mtr.global_suppressions OK
109+
mtr.test_suppressions OK
110+
sys.sys_config OK
111+
show create table mysql.innodb_index_stats;
112+
Table Create Table
113+
innodb_index_stats CREATE TABLE `innodb_index_stats` (
114+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
115+
`table_name` varchar(199) COLLATE utf8_bin NOT NULL,
116+
`index_name` varchar(64) COLLATE utf8_bin NOT NULL,
117+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
118+
`stat_name` varchar(64) COLLATE utf8_bin NOT NULL,
119+
`stat_value` bigint(20) unsigned NOT NULL,
120+
`sample_size` bigint(20) unsigned DEFAULT NULL,
121+
`stat_description` varchar(1024) COLLATE utf8_bin NOT NULL,
122+
PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
123+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
124+
show create table mysql.innodb_table_stats;
125+
Table Create Table
126+
innodb_table_stats CREATE TABLE `innodb_table_stats` (
127+
`database_name` varchar(64) COLLATE utf8_bin NOT NULL,
128+
`table_name` varchar(199) COLLATE utf8_bin NOT NULL,
129+
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
130+
`n_rows` bigint(20) unsigned NOT NULL,
131+
`clustered_index_size` bigint(20) unsigned NOT NULL,
132+
`sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
133+
PRIMARY KEY (`database_name`,`table_name`)
134+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
-- source include/have_innodb.inc
2+
-- source include/mysql_upgrade_preparation.inc
3+
--echo #
4+
--echo # Bug26390736 THE FIELD TABLE_NAME (VARCHAR(64)) FROM MYSQL.INNODB_TABLE_STATS CAN OVERFLOW
5+
--echo #
6+
#Test 1 Table with maximum possible name
7+
8+
show create table mysql.innodb_index_stats;
9+
show create table mysql.innodb_table_stats;
10+
11+
create table abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij (id int) engine=innodb
12+
partition by range (id)
13+
subpartition by hash(id) (
14+
15+
partition pbcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij values less than (10) (
16+
17+
subpartition subdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij,
18+
subpartition s02
19+
),
20+
partition pmax VALUES LESS THAN MAXVALUE (
21+
subpartition pmax_sub1,
22+
subpartition pmax_sub2
23+
)
24+
);
25+
26+
--replace_regex /#P#/#p#/ /#SP#/#sp#/
27+
select table_name,LENGTH(table_name) from mysql.innodb_table_stats where LENGTH(table_name) = 199;
28+
--replace_regex /#P#/#p#/ /#SP#/#sp#/
29+
select table_name,LENGTH(table_name) from mysql.innodb_index_stats where LENGTH(table_name) = 199;
30+
drop table abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghij;
31+
32+
#Test 2 Check mysql-upgrade
33+
34+
#Manually change length
35+
CALL mtr.add_suppression("Table mysql/innodb_table_stats has length mismatch in the column name table_name. Please run mysql_upgrade");
36+
CALL mtr.add_suppression("Table mysql/innodb_index_stats has length mismatch in the column name table_name. Please run mysql_upgrade");
37+
alter table mysql.innodb_table_stats modify table_name varchar(64);
38+
alter table mysql.innodb_index_stats modify table_name varchar(64);
39+
40+
show create table mysql.innodb_index_stats;
41+
show create table mysql.innodb_table_stats;
42+
43+
#Run upgrade to check if the length has changed.
44+
--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
45+
46+
show create table mysql.innodb_index_stats;
47+
show create table mysql.innodb_table_stats;
48+
49+
--source include/mysql_upgrade_cleanup.inc

scripts/mysql_system_tables.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
1+
-- Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
22
--
33
-- This program is free software; you can redistribute it and/or modify
44
-- it under the terms of the GNU General Public License as published by
@@ -92,7 +92,7 @@ SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION';
9292

9393
SET @create_innodb_table_stats="CREATE TABLE IF NOT EXISTS innodb_table_stats (
9494
database_name VARCHAR(64) NOT NULL,
95-
table_name VARCHAR(64) NOT NULL,
95+
table_name VARCHAR(199) NOT NULL,
9696
last_update TIMESTAMP NOT NULL NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
9797
n_rows BIGINT UNSIGNED NOT NULL,
9898
clustered_index_size BIGINT UNSIGNED NOT NULL,
@@ -102,7 +102,7 @@ SET @create_innodb_table_stats="CREATE TABLE IF NOT EXISTS innodb_table_stats (
102102

103103
SET @create_innodb_index_stats="CREATE TABLE IF NOT EXISTS innodb_index_stats (
104104
database_name VARCHAR(64) NOT NULL,
105-
table_name VARCHAR(64) NOT NULL,
105+
table_name VARCHAR(199) NOT NULL,
106106
index_name VARCHAR(64) NOT NULL,
107107
last_update TIMESTAMP NOT NULL NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
108108
/* there are at least:

scripts/mysql_system_tables_fix.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,3 +1041,11 @@ EXECUTE stmt;
10411041
DROP PREPARE stmt;
10421042

10431043
FLUSH PRIVILEGES;
1044+
1045+
--
1046+
-- Update the column length of 'table_name' column for stats tables.
1047+
--
1048+
1049+
alter table mysql.innodb_table_stats modify table_name varchar(199);
1050+
alter table mysql.innodb_index_stats modify table_name varchar(199);
1051+

0 commit comments

Comments
 (0)