Skip to content

Commit 60125a7

Browse files
MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0 in ha_innobase::estimate_rows_upper_bound
- Column stat_value and sample_size in mysql.innodb_index_stats table is declared as BIGINT UNSIGNED without any check constraint. user manually updates the value of stat_value and sample_size to zero. InnoDB aborts the server while reading the statistics information because InnoDB expects at least one leaf page to exist for the index. - To fix this issue, InnoDB should interpret the value of stat_n_leaf_pages, stat_index_size in innodb_index_stats stat_clustered_index_size, stat_sum_of_other_index_sizes in innodb_table_stats as valid one even though user mentioned it as 0.
1 parent d0a2d4e commit 60125a7

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,13 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL LIMIT ROWS EXAMINED 5;
174174
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN LIMIT ROWS EXAMINED 5;
175175
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS LIMIT ROWS EXAMINED 5;
176176
DROP TABLE t1;
177+
#
178+
# MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0
179+
# in ha_innobase::estimate_rows_upper_bound
180+
#
181+
CREATE TABLE t (c1 INT,c2 INT,
182+
INDEX(c1))STATS_PERSISTENT=1 ENGINE=INNODB;
183+
UPDATE mysql.innodb_index_stats SET stat_value=0 WHERE database_name like "test" and table_name like 't';
184+
UPDATE mysql.innodb_table_stats SET clustered_index_size= 0, sum_of_other_index_sizes=0 WHERE database_name like "test" and table_name like 't';
185+
UPDATE t SET c1=+1 ORDER BY c2;
186+
DROP TABLE t;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,15 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL LIMIT ROWS EXAMINED 5;
9696
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN LIMIT ROWS EXAMINED 5;
9797
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS LIMIT ROWS EXAMINED 5;
9898
DROP TABLE t1;
99+
100+
--echo #
101+
--echo # MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0
102+
--echo # in ha_innobase::estimate_rows_upper_bound
103+
--echo #
104+
105+
CREATE TABLE t (c1 INT,c2 INT,
106+
INDEX(c1))STATS_PERSISTENT=1 ENGINE=INNODB;
107+
UPDATE mysql.innodb_index_stats SET stat_value=0 WHERE database_name like "test" and table_name like 't';
108+
UPDATE mysql.innodb_table_stats SET clustered_index_size= 0, sum_of_other_index_sizes=0 WHERE database_name like "test" and table_name like 't';
109+
UPDATE t SET c1=+1 ORDER BY c2;
110+
DROP TABLE t;

storage/innobase/dict/dict0stats.cc

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,25 +2665,34 @@ dict_stats_fetch_table_stats_step(
26652665
break;
26662666

26672667
case 1: /* mysql.innodb_table_stats.clustered_index_size */
2668-
2668+
{
26692669
ut_a(dtype_get_mtype(type) == DATA_INT);
26702670
ut_a(len == 8);
26712671

26722672
table->stat_clustered_index_size
2673-
= (ulint) mach_read_from_8(data);
2674-
2673+
= std::max<ulint>(mach_read_from_8(data), 1);
26752674
break;
2675+
}
26762676

26772677
case 2: /* mysql.innodb_table_stats.sum_of_other_index_sizes */
2678-
2678+
{
26792679
ut_a(dtype_get_mtype(type) == DATA_INT);
26802680
ut_a(len == 8);
26812681

2682-
table->stat_sum_of_other_index_sizes
2682+
ulint stat_other_idx_size
26832683
= (ulint) mach_read_from_8(data);
2684+
if (!stat_other_idx_size
2685+
&& UT_LIST_GET_LEN(table->indexes) > 1) {
2686+
stat_other_idx_size
2687+
= UT_LIST_GET_LEN(table->indexes) - 1;
2688+
}
2689+
table->stat_sum_of_other_index_sizes
2690+
= std::max<ulint>(
2691+
mach_read_from_8(data),
2692+
UT_LIST_GET_LEN(table->indexes) - 1);
26842693

26852694
break;
2686-
2695+
}
26872696
default:
26882697

26892698
/* someone changed SELECT
@@ -2866,12 +2875,14 @@ dict_stats_fetch_index_stats_step(
28662875

28672876
if (stat_name_len == 4 /* strlen("size") */
28682877
&& strncasecmp("size", stat_name, stat_name_len) == 0) {
2869-
index->stat_index_size = (ulint) stat_value;
2878+
index->stat_index_size
2879+
= std::max<ulint>(stat_value, 1);
28702880
arg->stats_were_modified = true;
28712881
} else if (stat_name_len == 12 /* strlen("n_leaf_pages") */
28722882
&& strncasecmp("n_leaf_pages", stat_name, stat_name_len)
28732883
== 0) {
2874-
index->stat_n_leaf_pages = (ulint) stat_value;
2884+
index->stat_n_leaf_pages
2885+
= std::max<ulint>(stat_value, 1);
28752886
arg->stats_were_modified = true;
28762887
} else if (stat_name_len == 12 /* strlen("n_page_split") */
28772888
&& strncasecmp("n_page_split", stat_name, stat_name_len)
@@ -2951,7 +2962,8 @@ dict_stats_fetch_index_stats_step(
29512962
index->stat_n_diff_key_vals[n_pfx - 1] = stat_value;
29522963

29532964
if (sample_size != UINT64_UNDEFINED) {
2954-
index->stat_n_sample_sizes[n_pfx - 1] = sample_size;
2965+
index->stat_n_sample_sizes[n_pfx - 1] =
2966+
std::max<ib_uint64_t>(sample_size, 1);
29552967
} else {
29562968
/* hmm, strange... the user must have UPDATEd the
29572969
table manually and SET sample_size = NULL */

0 commit comments

Comments
 (0)