diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2016-12-09 17:13:43 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2016-12-09 17:13:43 +0400 |
commit | 83f7151da5259fa07ab2c26600009d53adef50f3 (patch) | |
tree | 39c8f971be55aabd9e294a534fd8b6f448374af9 /sql/sql_statistics.cc | |
parent | 870d7589c6c4596b0f1a641add5071469e2c94a7 (diff) | |
download | mariadb-git-83f7151da5259fa07ab2c26600009d53adef50f3.tar.gz |
MDEV-10435 crash with bad stat tables.
Functions from sql/statistics.cc don't seem to expect
stat tables to fail or to have inadequate structure.
Table open errors suppressed and some validity
checks added. Invalid tables reported to the server
log.
Diffstat (limited to 'sql/sql_statistics.cc')
-rw-r--r-- | sql/sql_statistics.cc | 157 |
1 files changed, 145 insertions, 12 deletions
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 27bc0fb4cd3..62d56a700b8 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -129,6 +129,128 @@ inline void init_table_list_for_single_stat_table(TABLE_LIST *tbl, } +static Table_check_intact_log_error stat_table_intact; + +static const +TABLE_FIELD_TYPE table_stat_fields[TABLE_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("cardinality") }, + { C_STRING_WITH_LEN("bigint(21)") }, + { NULL, 0 } + }, +}; +static const uint table_stat_pk_col[]= {0,1}; +static const TABLE_FIELD_DEF +table_stat_def= {TABLE_STAT_N_FIELDS, table_stat_fields, 2, table_stat_pk_col }; + +static const +TABLE_FIELD_TYPE column_stat_fields[COLUMN_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("column_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("min_value") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("max_value") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("nulls_ratio") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_length") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_frequency") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("hist_size") }, + { C_STRING_WITH_LEN("tinyint(3)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("hist_type") }, + { C_STRING_WITH_LEN("enum('SINGLE_PREC_HB','DOUBLE_PREC_HB')") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("histogram") }, + { C_STRING_WITH_LEN("varbinary(255)") }, + { NULL, 0 } + } +}; +static const uint column_stat_pk_col[]= {0,1,2}; +static const TABLE_FIELD_DEF +column_stat_def= {COLUMN_STAT_N_FIELDS, column_stat_fields, 3, column_stat_pk_col}; + +static const +TABLE_FIELD_TYPE index_stat_fields[INDEX_STAT_N_FIELDS] = +{ + { + { C_STRING_WITH_LEN("db_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("table_name") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("index") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("prefix_arity") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("avg_frequency") }, + { C_STRING_WITH_LEN("decimal(12,4)") }, + { NULL, 0 } + } +}; +static const uint index_stat_pk_col[]= {0,1,2,3}; +static const TABLE_FIELD_DEF +index_stat_def= {INDEX_STAT_N_FIELDS, index_stat_fields, 4, index_stat_pk_col}; + + /** @brief Open all statistical tables and lock them @@ -139,10 +261,30 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables, Open_tables_backup *backup, bool for_write) { + int rc; + + Dummy_error_handler deh; // suppress errors + thd->push_internal_handler(&deh); init_table_list_for_stat_tables(tables, for_write); init_mdl_requests(tables); - return open_system_tables_for_read(thd, tables, backup); -} + rc= open_system_tables_for_read(thd, tables, backup); + thd->pop_internal_handler(); + + + /* If the number of tables changes, we should revise the check below. */ + DBUG_ASSERT(STATISTICS_TABLES == 3); + + if (!rc && + (stat_table_intact.check(tables[TABLE_STAT].table, &table_stat_def) || + stat_table_intact.check(tables[COLUMN_STAT].table, &column_stat_def) || + stat_table_intact.check(tables[INDEX_STAT].table, &index_stat_def))) + { + close_system_tables(thd, backup); + rc= 1; + } + + return rc; +} /** @@ -2725,10 +2867,7 @@ int update_statistics_for_table(THD *thd, TABLE *table) DEBUG_SYNC(thd, "statistics_update_start"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); DBUG_RETURN(rc); - } save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); @@ -3156,10 +3295,7 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab) DBUG_ENTER("delete_statistics_for_table"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); DBUG_RETURN(rc); - } save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); @@ -3398,10 +3534,7 @@ int rename_table_in_stat_tables(THD *thd, LEX_STRING *db, LEX_STRING *tab, DBUG_ENTER("rename_table_in_stat_tables"); if (open_stat_tables(thd, tables, &open_tables_backup, TRUE)) - { - thd->clear_error(); - DBUG_RETURN(rc); - } + DBUG_RETURN(0); // not an error save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); |