Commit e3b36b8f authored by Monty's avatar Monty

MDEV-31957 Concurrent ALTER and ANALYZE collecting statistics can result in stale statistical data

Example of what causes the problem:
T1: ANALYZE TABLE starts to collect statistics
T2: ALTER TABLE starts by deleting statistics for all changed fields,
    then creates a temp table and copies data to it.
T1: ANALYZE ends and writes to the statistics tables.
T2: ALTER TABLE renames temp table in place of the old table.

Now the statistics from analyze matches the old deleted tables.

Fixed by waiting to delete old statistics until ALTER TABLE is
the only one using the old table and ensure that rename of columns
can handle swapping of column names.

rename_columns_in_stat_table() (former rename_column_in_stat_tables())
now takes a list of columns to rename. It uses the following algorithm
to update column_stats to be able to handle circular renames

- While there are columns to be renamed and it is the first loop or
  last rename loop did change something.
  - Loop over all columns to be renamed
    - Change column name in column_stat
      - If fail because of duplicate key
      - If this is first change attempt for this column
         - Change column name to a temporary column name
         - If there was a conflicting row, replace it with the current row.
    else
     - Remove entry from column list

- Loop over all remaining columns in the list
 - Remove the conflicting row
 - Change column from temporary name to final name in column_stat

Other things:
- Don't flush tables for every operation. Only flush when all updates
  are done.
- Rename of columns was not handled in case of ALGORITHM=copy (old bug).
  - Fixed that we do not collect statistics for hidden hash columns
    used by UNIQUE constraint on long values.
  - Fixed that we do not collect statistics for blob columns referred by
    generated virtual columns. This was achieved by storing the fields for
    which we want to have statistics in table->has_value_set instead of
    in table->read_set.
- Rename of indexes was not handled for persistent statistics.
  - This is now handled similar as rename of columns. Renamed columns
    are now stored in 'rename_stat_indexes' and handled in
    Alter_info::delete_statistics() together with drooped indexes.
- ALTER TABLE .. ADD INDEX may instead of creating a new index rename
  an existing generated foreign key index. This was not reflected in
  the index_stats table because this was handled in
  mysql_prepare_create_table instead instead of in the mysql_alter() code.
  Fixed by adding a call in mysql_prepare_create_table() to drop the
  changed index.
  I also had to change the code that 'marked the index' to be ignored
  with code that would not destroy the original index name.

Reviewer: Sergei Petrunia <sergey@mariadb.com>
parent 388296a1
This diff is collapsed.
--source include/have_sequence.inc
--source include/have_innodb.inc
#
# Bug #10901 Analyze Table on new table destroys table
......@@ -111,6 +112,148 @@ set use_stat_tables=default;
set histogram_type=default;
set histogram_size=default;
--echo #
--echo # MDEV-31957 Concurrent ALTER and ANALYZE collecting statistics can
--echo # result in stale statistical data
--echo #
CREATE TABLE t1 (a INT, b VARCHAR(128));
INSERT INTO t1 SELECT seq, CONCAT('s',seq) FROM seq_1_to_100;
# We have to disable query log as the ANALYZE TABLE can be run in different
# order. The important thing is what is finally in column_stats
--disable_result_log
--connect (con1,localhost,root,,)
--send ALTER TABLE t1 MODIFY b BLOB
--connection default
ANALYZE TABLE t1 PERSISTENT FOR ALL;
--connection con1
--reap
ANALYZE TABLE t1 PERSISTENT FOR ALL;
--connection default
--disconnect con1
--enable_result_log
select db_name,table_name,column_name from mysql.column_stats;
drop table t1;
--echo #
--echo # Testing swapping columns
--echo #
create or replace table t1 (a int primary key, b varchar(100), c varchar(100), d varchar(100)) engine=innodb;
insert into t1 select seq, repeat('b',seq),repeat('c',mod(seq,5)), repeat('d',mod(seq,10)) from seq_1_to_100;
ANALYZE TABLE t1 PERSISTENT FOR ALL;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change b c varchar(200), change c b varchar(200);
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change b c varchar(200), change c d varchar(200), change d b varchar(200) ;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change b c varchar(200), change c d varchar(200), change d e varchar(200) ;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change e d varchar(200), drop column d;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
--echo # Test having non existing column in column_stats
insert into mysql.column_stats (db_name,table_name,column_name) values ("test","t1","b");
alter table t1 change c d varchar(200), change d b varchar(200);
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
--echo # Test having a conflicting temporary name
insert into mysql.column_stats (db_name,table_name,column_name) values ("test","t1",concat("#sql_tmp_name#1",char(0)));
alter table t1 change d b varchar(200), change b d varchar(200);
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
drop table t1;
truncate table mysql.column_stats;
create or replace table t1 (a int primary key, b varchar(100), c varchar(100), d varchar(100)) engine=myisam;
insert into t1 select seq, repeat('b',seq),repeat('c',mod(seq,5)), repeat('d',mod(seq,10)) from seq_1_to_100;
ANALYZE TABLE t1 PERSISTENT FOR ALL;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change b c varchar(200), change c b varchar(200);
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
analyze table t1 persistent for columns(b,c) indexes all;
alter table t1 change b c varchar(200), change c d varchar(200), change d b varchar(200) ;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
analyze table t1 persistent for columns(d) indexes all;
alter table t1 change b c varchar(200), change c d varchar(200), change d e varchar(200) ;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
alter table t1 change e d varchar(200), drop column d;
select db_name,table_name,column_name,avg_length from mysql.column_stats order by column_name;
drop table t1;
truncate table mysql.column_stats;
create table t1 (a int, b blob, unique(b)) engine= innodb;
analyze table t1 persistent for all;
select column_name from mysql.column_stats where table_name = 't1';
drop table t1;
create table t1 (a int, b blob, c int generated always as (length(b)) virtual) engine= innodb;
analyze table t1 persistent for all;
select column_name from mysql.column_stats where table_name = 't1';
drop table t1;
CREATE or replace TABLE t1 (a INT, b CHAR(8));
ANALYZE TABLE t1 PERSISTENT FOR ALL;
ALTER TABLE t1 CHANGE b c INT, ORDER BY b;
SELECT db_name, table_name, column_name FROM mysql.column_stats where table_name = 't1';
drop table t1;
CREATE or replace TABLE t1 (a INT, b CHAR(8));
ANALYZE TABLE t1 PERSISTENT FOR ALL;
ALTER TABLE t1 RENAME COLUMN b to c, ALGORITHM=COPY;
SELECT db_name, table_name, column_name FROM mysql.column_stats where table_name = 't1';
drop table t1;
--echo #
--echo # Testing swapping indexes
--echo #
create or replace table t1 (a int primary key, b varchar(100), c varchar(100), d varchar(100), index (b), index(c), index(d,b)) engine=innodb;
insert into t1 select seq, repeat('b',seq),repeat('c',mod(seq,5)), repeat('d',mod(seq,10)) from seq_1_to_100;
ANALYZE TABLE t1 PERSISTENT FOR ALL;
select * from mysql.index_stats order by index_name, prefix_arity;
alter table t1 rename index b to c, rename index c to d, rename index d to b;
select * from mysql.index_stats order by index_name;
alter table t1 rename index b to c, rename index c to d, rename index d to e;
select * from mysql.index_stats order by index_name, prefix_arity;
alter table t1 rename index e to b;
alter table t1 change b c varchar(200), change c d varchar(200), change d e varchar(200) ;
show create table t1;
select * from mysql.index_stats order by index_name, prefix_arity;
--echo # Test having a conflicting temporary name
insert into mysql.index_stats (db_name,table_name,index_name,prefix_arity) values ("test","t1",concat("#sql_tmp_name#1",char(0)),1);
alter table t1 rename index c to d, rename index d to c;
select * from mysql.index_stats order by index_name, prefix_arity;
drop table t1;
select * from mysql.index_stats order by index_name, prefix_arity;
--echo #
--echo # Test of adding key that replaces foreign key
--echo #
CREATE TABLE t1 (aaaa INT, b INT, KEY(b), FOREIGN KEY(aaaa) REFERENCES t1(b)) ENGINE=InnoDB;
ANALYZE TABLE t1 PERSISTENT FOR ALL;
SELECT index_name FROM mysql.index_stats WHERE table_name = 't1' order by index_name;
ALTER TABLE t1 ADD KEY idx(aaaa);
SHOW CREATE TABLE t1;
SELECT index_name FROM mysql.index_stats WHERE table_name = 't1' order by index_name;
truncate table mysql.index_stats;
ANALYZE TABLE t1 PERSISTENT FOR ALL;
SELECT index_name FROM mysql.index_stats WHERE table_name = 't1' order by index_name;
--error ER_DROP_INDEX_FK
ALTER TABLE t1 DROP KEY idx;
DROP TABLE t1;
--echo #
--echo # End of 10.6 tests
--echo #
......@@ -552,6 +552,13 @@ test t1 PRIMARY 1 1.0000
test t1 idx2 1 7.0000
test t1 idx2 2 2.3846
test t1 idx3 1 8.5000
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(x) INDEXES();
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SELECT * FROM mysql.column_stats where column_name="x";
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t1 x vvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz 0.2000 17.1250 6.4000 0 NULL NULL
ALTER TABLE t1 CHANGE COLUMN x b varchar(32);
SHOW CREATE TABLE t1;
Table Create Table
......@@ -668,8 +675,8 @@ test t1 PRIMARY 1 1.0000
test t1 idx2 1 7.0000
test t1 idx2 2 2.3846
test t1 idx3 1 8.5000
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/save_column_stats'
INTO TABLE mysql.column_stats
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/save_column_stats' IGNORE
INTO TABLE mysql.column_stats
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/save_index_stats'
INTO TABLE mysql.index_stats
......@@ -1106,12 +1113,17 @@ test t2 idx4 1 6.2000
test t2 idx4 2 1.7222
test t2 idx4 3 1.1154
test t2 idx4 4 1.0000
SELECT * FROM mysql.column_stats where column_name="b";
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t2 b vvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz 0.2000 17.1250 6.4000 0 NULL NULL
ALTER TABLE t2 CHANGE COLUMN b b varchar(30);
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
db_name table_name index_name prefix_arity avg_frequency
test t2 idx2 1 7.0000
test t2 idx2 2 2.3846
test t2 idx3 1 8.5000
SELECT * FROM mysql.column_stats where column_name="b";
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL;
Table Op Msg_type Msg_text
test.t2 analyze status Engine-independent statistics collected
......@@ -1147,6 +1159,9 @@ test t2 idx4 1 6.2000
test t2 idx4 2 1.7222
test t2 idx4 3 1.1154
test t2 idx4 4 1.0000
SELECT * FROM mysql.column_stats where column_name="b";
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t2 b 0 zzzzzzzzzzzzzzzzzz 0.0000 13.9000 6.6667 0 NULL NULL
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL;
Table Op Msg_type Msg_text
test.t2 analyze status Engine-independent statistics collected
......
......@@ -305,6 +305,10 @@ SELECT * FROM mysql.column_stats;
--sorted_result
SELECT * FROM mysql.index_stats;
# Add 'x' back that was deleted above
ANALYZE TABLE t1 PERSISTENT FOR COLUMNS(x) INDEXES();
SELECT * FROM mysql.column_stats where column_name="x";
ALTER TABLE t1 CHANGE COLUMN x b varchar(32);
SHOW CREATE TABLE t1;
--sorted_result
......@@ -347,7 +351,7 @@ SELECT * FROM mysql.index_stats;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval
LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/save_column_stats'
LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/save_column_stats' IGNORE
INTO TABLE mysql.column_stats
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n';
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
......@@ -495,14 +499,17 @@ SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL;
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
SELECT * FROM mysql.column_stats where column_name="b";
ALTER TABLE t2 CHANGE COLUMN b b varchar(30);
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
SELECT * FROM mysql.column_stats where column_name="b";
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL;
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
ALTER TABLE t2 CHANGE COLUMN b b varchar(32);
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
SELECT * FROM mysql.column_stats where column_name="b";
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL;
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
......
......@@ -517,8 +517,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
List<Item> field_list;
Protocol *protocol= thd->protocol;
LEX *lex= thd->lex;
int result_code;
int compl_result_code;
bool need_repair_or_alter= 0;
wait_for_commit* suspended_wfc;
bool is_table_modified= false;
......@@ -562,7 +560,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
bool collect_eis= FALSE;
bool open_for_modify= org_open_for_modify;
Recreate_info recreate_info;
int compl_result_code, result_code;
compl_result_code= result_code= HA_ADMIN_FAILED;
storage_engine_name[0]= 0; // Marker that's not used
DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str));
......@@ -880,6 +880,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_PRINT("admin", ("operator_func returned: %d", result_code));
}
/* Note: compl_result_code can be different from result_code here */
if (compl_result_code == HA_ADMIN_OK && collect_eis)
{
if (result_code == HA_ERR_TABLE_READONLY)
......@@ -920,19 +921,35 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
Field **field_ptr= tab->field;
if (!lex->column_list)
{
/* Fields we have to read from the engine */
bitmap_clear_all(tab->read_set);
/* Fields we want to have statistics for */
bitmap_clear_all(&tab->has_value_set);
for (uint fields= 0; *field_ptr; field_ptr++, fields++)
{
Field *field= *field_ptr;
if (field->flags & LONG_UNIQUE_HASH_FIELD)
{
/*
No point in doing statistic for hash fields that should be
unique
*/
continue;
}
/*
Note that type() always return MYSQL_TYPE_BLOB for
all blob types. Another function needs to be added
if we in the future want to distingush between blob
types here.
*/
enum enum_field_types type= (*field_ptr)->type();
enum enum_field_types type= field->type();
if (type < MYSQL_TYPE_TINY_BLOB ||
type > MYSQL_TYPE_BLOB)
tab->field[fields]->register_field_in_read_map();
{
field->register_field_in_read_map();
bitmap_set_bit(&tab->has_value_set, field->field_index);
}
else
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NO_EIS_FOR_FIELD,
......@@ -946,9 +963,15 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
LEX_STRING *column_name;
List_iterator_fast<LEX_STRING> it(*lex->column_list);
/* Fields we have to read from the engine */
bitmap_clear_all(tab->read_set);
/* Fields we want to have statistics for */
bitmap_clear_all(&tab->has_value_set);
while ((column_name= it++))
{
Field *field;
enum enum_field_types type;
if (tab->s->fieldnames.type_names == 0 ||
(pos= find_type(&tab->s->fieldnames, column_name->str,
column_name->length, 1)) <= 0)
......@@ -957,10 +980,15 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
break;
}
pos--;
enum enum_field_types type= tab->field[pos]->type();
if (type < MYSQL_TYPE_TINY_BLOB ||
type > MYSQL_TYPE_BLOB)
tab->field[pos]->register_field_in_read_map();
field= tab->field[pos];
type= field->type();
if (!(field->flags & LONG_UNIQUE_HASH_FIELD) &&
(type < MYSQL_TYPE_TINY_BLOB ||
type > MYSQL_TYPE_BLOB))
{
field->register_field_in_read_map();
bitmap_set_bit(&tab->has_value_set, field->field_index);
}
else
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NO_EIS_FOR_FIELD,
......@@ -991,12 +1019,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
}
/* Ensure that number of records are updated */
table->table->file->info(HA_STATUS_VARIABLE);
tab->file->info(HA_STATUS_VARIABLE);
if (!(compl_result_code=
alloc_statistics_for_table(thd, table->table)) &&
alloc_statistics_for_table(thd, tab,
&tab->has_value_set)) &&
!(compl_result_code=
collect_statistics_for_table(thd, table->table)))
compl_result_code= update_statistics_for_table(thd, table->table);
collect_statistics_for_table(thd, tab)))
compl_result_code= update_statistics_for_table(thd, tab);
}
else
compl_result_code= HA_ADMIN_FAILED;
......
......@@ -18,6 +18,7 @@
#include "sql_parse.h" // check_access
#include "sql_table.h" // mysql_alter_table,
// mysql_exchange_partition
#include "sql_statistics.h" // delete_statistics_for_column
#include "sql_alter.h"
#include "wsrep_mysqld.h"
......@@ -31,6 +32,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
check_constraint_list(rhs.check_constraint_list, mem_root),
flags(rhs.flags), partition_flags(rhs.partition_flags),
keys_onoff(rhs.keys_onoff),
original_table(0),
partition_names(rhs.partition_names, mem_root),
num_parts(rhs.num_parts),
requested_algorithm(rhs.requested_algorithm),
......@@ -297,6 +299,79 @@ uint Alter_info::check_vcol_field(Item_field *item) const
}
bool Alter_info::collect_renamed_fields(THD *thd)
{
List_iterator_fast<Create_field> new_field_it;
Create_field *new_field;
DBUG_ENTER("Alter_info::collect_renamed_fields");
new_field_it.init(create_list);
while ((new_field= new_field_it++))
{
Field *field= new_field->field;
if (new_field->field &&
cmp(&field->field_name, &new_field->field_name))
{
field->flags|= FIELD_IS_RENAMED;
if (add_stat_rename_field(field,
&new_field->field_name,
thd->mem_root))
DBUG_RETURN(true);
}
}
DBUG_RETURN(false);
}
/*
Delete duplicate index found during mysql_prepare_create_table()
Notes:
- In case of temporary generated foreign keys, the key_name may not
be set! These keys are ignored.
*/
bool Alter_info::add_stat_drop_index(THD *thd, const LEX_CSTRING *key_name)
{
if (original_table && key_name->length) // If from alter table
{
KEY *key_info= original_table->key_info;
for (uint i= 0; i < original_table->s->keys; i++, key_info++)
{
if (key_info->name.length &&
!lex_string_cmp(system_charset_info, &key_info->name,
key_name))
return add_stat_drop_index(key_info, false, thd->mem_root);
}
}
return false;
}
void Alter_info::apply_statistics_deletes_renames(THD *thd, TABLE *table)
{
List_iterator<Field> it_drop_field(drop_stat_fields);
List_iterator<RENAME_COLUMN_STAT_PARAMS> it_rename_field(rename_stat_fields);
List_iterator<DROP_INDEX_STAT_PARAMS> it_drop_index(drop_stat_indexes);
List_iterator<RENAME_INDEX_STAT_PARAMS> it_rename_index(rename_stat_indexes);
while (Field *field= it_drop_field++)
delete_statistics_for_column(thd, table, field);
if (!rename_stat_fields.is_empty())
(void) rename_columns_in_stat_table(thd, table, &rename_stat_fields);
while (DROP_INDEX_STAT_PARAMS *key= it_drop_index++)
(void) delete_statistics_for_index(thd, table, key->key,
key->ext_prefixes_only);
if (!rename_stat_indexes.is_empty())
(void) rename_indexes_in_stat_table(thd, table, &rename_stat_indexes);
}
Alter_table_ctx::Alter_table_ctx()
: db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str)
......
......@@ -105,10 +105,88 @@ class Alter_info
ulong partition_flags;
// Enable or disable keys.
enum_enable_or_disable keys_onoff;
// Used only in add_stat_drop_index()
TABLE *original_table;
// List of partitions.
List<const char> partition_names;
// Number of partitions.
uint num_parts;
/* List of fields that we should delete statistics from */
List<Field> drop_stat_fields;
struct DROP_INDEX_STAT_PARAMS
{
KEY *key;
bool ext_prefixes_only;
};
struct RENAME_COLUMN_STAT_PARAMS
{
Field *field;
LEX_CSTRING *name;
uint duplicate_counter; // For temporary names
};
struct RENAME_INDEX_STAT_PARAMS
{
const KEY *key;
const LEX_CSTRING *name;
uint duplicate_counter; // For temporary names
uint usage_count; // How many rename entries
};
/* List of index that we should delete statistics from */
List<DROP_INDEX_STAT_PARAMS> drop_stat_indexes;
List<RENAME_COLUMN_STAT_PARAMS> rename_stat_fields;
List<RENAME_INDEX_STAT_PARAMS> rename_stat_indexes;
bool add_stat_drop_index(KEY *key, bool ext_prefixes_only,
MEM_ROOT *mem_root)
{
DROP_INDEX_STAT_PARAMS *param;
if (!(param= (DROP_INDEX_STAT_PARAMS*)
alloc_root(mem_root, sizeof(*param))))
return true;
param->key= key;
param->ext_prefixes_only= ext_prefixes_only;
return drop_stat_indexes.push_back(param, mem_root);
}
bool add_stat_drop_index(THD *thd, const LEX_CSTRING *key_name);
bool add_stat_rename_index(const KEY *key, const LEX_CSTRING *name,
MEM_ROOT *mem_root)
{
RENAME_INDEX_STAT_PARAMS *param;
if (!(param= (RENAME_INDEX_STAT_PARAMS*)
alloc_root(mem_root, sizeof(*param))))
return true;
param->key= key;
param->name= name;
param->usage_count= 0;
return rename_stat_indexes.push_back(param, mem_root);
}
bool add_stat_rename_field(Field *field, LEX_CSTRING *name,
MEM_ROOT *mem_root)
{
RENAME_COLUMN_STAT_PARAMS *param;
if (!(param= (RENAME_COLUMN_STAT_PARAMS*)
alloc_root(mem_root, sizeof(*param))))
return true;
param->field= field;
param->name= name;
param->duplicate_counter= 0;
return rename_stat_fields.push_back(param, mem_root);
}
bool collect_renamed_fields(THD *thd);
/* Delete/update statistics in EITS tables */
void apply_statistics_deletes_renames(THD *thd, TABLE *table);
private:
// Type of ALTER TABLE algorithm.
enum_alter_table_algorithm requested_algorithm;
......@@ -135,6 +213,10 @@ class Alter_info
create_list.empty();
alter_index_ignorability_list.empty();
check_constraint_list.empty();
drop_stat_fields.empty();
drop_stat_indexes.empty();
rename_stat_fields.empty();
rename_stat_indexes.empty();
flags= 0;
partition_flags= 0;
keys_onoff= LEAVE_AS_IS;
......
......@@ -444,7 +444,8 @@ class Alter_index_ignorability: public Sql_alloc
class Key :public Sql_alloc, public DDL_options {
public:
enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY,
IGNORE_KEY};
enum Keytype type;
KEY_CREATE_INFO key_create_info;
List<Key_part_spec> columns;
......
This diff is collapsed.
......@@ -119,16 +119,21 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables);
int read_statistics_for_tables(THD *thd, TABLE_LIST *tables,
bool force_reload);
int collect_statistics_for_table(THD *thd, TABLE *table);
int alloc_statistics_for_table(THD *thd, TABLE *table);
int alloc_statistics_for_table(THD *thd, TABLE *table, MY_BITMAP *stat_fields);
int update_statistics_for_table(THD *thd, TABLE *table);
int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab);
int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db,
const LEX_CSTRING *tab);
int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col);
int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info,
bool ext_prefixes_only);
int rename_table_in_stat_tables(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab,
const LEX_CSTRING *new_db, const LEX_CSTRING *new_tab);
int rename_column_in_stat_tables(THD *thd, TABLE *tab, Field *col,
const char *new_name);
int rename_table_in_stat_tables(THD *thd, const LEX_CSTRING *db,
const LEX_CSTRING *tab,
const LEX_CSTRING *new_db,
const LEX_CSTRING *new_tab);
int rename_columns_in_stat_table(THD *thd, TABLE *tab,
List<Alter_info::RENAME_COLUMN_STAT_PARAMS> *fields);
int rename_indexes_in_stat_table(THD *thd, TABLE *tab,
List<Alter_info::RENAME_INDEX_STAT_PARAMS> *indexes);
void set_statistics_for_table(THD *thd, TABLE *table);
double get_column_avg_frequency(Field * field);
......
This diff is collapsed.
......@@ -95,11 +95,11 @@ class engine_option_value;
struct ha_index_option_struct;
typedef struct st_key {
uint key_length; /* total length of user defined key parts */
ulong flags; /* dupp key and pack flags */
uint user_defined_key_parts; /* How many key_parts */
uint usable_key_parts; /* Should normally be = user_defined_key_parts */
uint ext_key_parts; /* Number of key parts in extended key */
uint key_length; /* total length of user defined key parts */
ulong flags; /* dupp key and pack flags */
uint user_defined_key_parts; /* How many key_parts */
uint usable_key_parts; /* Should normally be = user_defined_key_parts */
uint ext_key_parts; /* Number of key parts in extended key */
ulong ext_key_flags; /* Flags for extended key */
/*
Parts of primary key that are in the extension of this index.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment